1. Introduction and Aims

We have merged the two datasets together in GCSKO_merge.Rmd. We also subsetted out the pre-sexual-branch and the sexual cells (male and female) and stored them in a Seurat object called tenx.mutant.integrated.sex. Here, we will perform pseudotime analysis on the dataset and build modules of genes that show similar expression across this pseudotime.

2. Read in the data

Load/Install the Required Packages

[1] "patchwork is loaded correctly"
[1] "viridis is loaded correctly"
[1] "Seurat is loaded correctly"
[1] "cowplot is loaded correctly"
[1] "gridExtra is loaded correctly"
[1] "grid is loaded correctly"
[1] "Hmisc is loaded correctly"
[1] "reshape2 is loaded correctly"
[1] "dplyr is loaded correctly"
[1] "monocle3 is loaded correctly"
Loading required package: destiny
there is no package called ‘destiny’
[1] "trying to install destiny"
Bioconductor version 3.11 (BiocManager 1.30.10), R 4.0.2 (2020-06-22)
Installing package(s) 'destiny'
also installing the dependencies ‘DEoptimR’, ‘xts’, ‘robustbase’, ‘vcd’, ‘laeken’, ‘ranger’, ‘TTR’, ‘pcaMethods’, ‘ggplot.multistats’, ‘ggthemes’, ‘VIM’, ‘knn.covertree’, ‘smoother’, ‘scatterplot3d’

cannot open URL 'https://bioconductor.org/packages/3.11/data/annotation/bin/macosx/contrib/4.0/PACKAGES.rds': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/data/annotation/bin/macosx/contrib/4.0/PACKAGES.gz': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/data/experiment/bin/macosx/contrib/4.0/PACKAGES.rds': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/data/experiment/bin/macosx/contrib/4.0/PACKAGES.gz': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/workflows/bin/macosx/contrib/4.0/PACKAGES.rds': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/workflows/bin/macosx/contrib/4.0/PACKAGES.gz': HTTP status was '404 Not Found'Package which is only available in source form, and may need
  compilation of C/C++/Fortran: ‘destiny’
trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/DEoptimR_1.0-8.tgz'
Content type 'application/x-gzip' length 39620 bytes (38 KB)
==================================================
downloaded 38 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/xts_0.12.1.tgz'
Content type 'application/x-gzip' length 927873 bytes (906 KB)
==================================================
downloaded 906 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/robustbase_0.93-6.tgz'
Content type 'application/x-gzip' length 3300888 bytes (3.1 MB)
==================================================
downloaded 3.1 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/vcd_1.4-7.tgz'
Content type 'application/x-gzip' length 1557206 bytes (1.5 MB)
==================================================
downloaded 1.5 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/laeken_0.5.1.tgz'
Content type 'application/x-gzip' length 2913969 bytes (2.8 MB)
==================================================
downloaded 2.8 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/ranger_0.12.1.tgz'
Content type 'application/x-gzip' length 2003695 bytes (1.9 MB)
==================================================
downloaded 1.9 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/TTR_0.24.2.tgz'
Content type 'application/x-gzip' length 525804 bytes (513 KB)
==================================================
downloaded 513 KB

trying URL 'https://bioconductor.org/packages/3.11/bioc/bin/macosx/contrib/4.0/pcaMethods_1.80.0.tgz'
Content type 'application/x-gzip' length 1197476 bytes (1.1 MB)
==================================================
downloaded 1.1 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/ggplot.multistats_1.0.0.tgz'
Content type 'application/x-gzip' length 29775 bytes (29 KB)
==================================================
downloaded 29 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/ggthemes_4.2.0.tgz'
Content type 'application/x-gzip' length 426524 bytes (416 KB)
==================================================
downloaded 416 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/VIM_6.0.0.tgz'
Content type 'application/x-gzip' length 1738658 bytes (1.7 MB)
==================================================
downloaded 1.7 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/knn.covertree_1.0.tgz'
Content type 'application/x-gzip' length 686790 bytes (670 KB)
==================================================
downloaded 670 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/smoother_1.1.tgz'
Content type 'application/x-gzip' length 22584 bytes (22 KB)
==================================================
downloaded 22 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/scatterplot3d_0.3-41.tgz'
Content type 'application/x-gzip' length 333688 bytes (325 KB)
==================================================
downloaded 325 KB

The downloaded binary packages are in
    /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//RtmpXGhNV1/downloaded_packages
installing the source package ‘destiny’

trying URL 'https://bioconductor.org/packages/3.11/bioc/src/contrib/destiny_3.2.0.tar.gz'
Content type 'application/x-gzip' length 8979926 bytes (8.6 MB)
==================================================
downloaded 8.6 MB

* installing *source* package ‘destiny’ ...
** using staged installation
** libs
clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Rcpp/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/grDevices/include' -I/usr/local/include  -ggdb -fPIC  -Wall -g -O2  -c RcppExports.cpp -o RcppExports.o
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:1:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Core:535:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:2:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/LU:47:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:3:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Cholesky:12:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Jacobi:29:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:3:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Cholesky:43:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/QR:17:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Householder:27:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:5:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SVD:48:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:6:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Geometry:58:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Eigenvalues:58:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:26:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseCore:66:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:27:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/OrderingMethods:71:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:29:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseCholesky:43:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:32:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseQR:35:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:33:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/IterativeLinearSolvers:46:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:32:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/CholmodSupport:45:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:35:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/KroneckerProduct:34:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:39:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/Polynomials:135:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:40:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/SparseExtra:51:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
17 warnings generated.
clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Rcpp/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/grDevices/include' -I/usr/local/include  -ggdb -fPIC  -Wall -g -O2  -c censoring.cpp -o censoring.o
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:1:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Core:535:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:2:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/LU:47:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:3:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Cholesky:12:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Jacobi:29:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:3:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Cholesky:43:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/QR:17:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Householder:27:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:5:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SVD:48:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:6:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Geometry:58:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Eigenvalues:58:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:26:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseCore:66:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:27:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/OrderingMethods:71:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:29:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseCholesky:43:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:32:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseQR:35:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:33:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/IterativeLinearSolvers:46:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:32:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/CholmodSupport:45:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:35:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/KroneckerProduct:34:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:39:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/Polynomials:135:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:40:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/SparseExtra:51:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
censoring.cpp:60:15: warning: variable 'm0' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:71:20: note: uninitialized use occurs here
                                * ( std::erfc((m0-v) / sigma) - std::erfc((m1-v) / sigma) )
                                               ^~
censoring.cpp:60:11: note: remove the 'if' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:60:15: warning: variable 'm0' is used uninitialized whenever '&&' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~
censoring.cpp:71:20: note: uninitialized use occurs here
                                * ( std::erfc((m0-v) / sigma) - std::erfc((m1-v) / sigma) )
                                               ^~
censoring.cpp:60:15: note: remove the '&&' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~
censoring.cpp:55:13: note: initialize the variable 'm0' to silence this warning
                        double m0, m1;
                                 ^
                                  = 0.0
censoring.cpp:60:15: warning: variable 'm1' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:71:48: note: uninitialized use occurs here
                                * ( std::erfc((m0-v) / sigma) - std::erfc((m1-v) / sigma) )
                                                                           ^~
censoring.cpp:60:11: note: remove the 'if' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:60:15: warning: variable 'm1' is used uninitialized whenever '&&' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~
censoring.cpp:71:48: note: uninitialized use occurs here
                                * ( std::erfc((m0-v) / sigma) - std::erfc((m1-v) / sigma) )
                                                                           ^~
censoring.cpp:60:15: note: remove the '&&' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~
censoring.cpp:55:17: note: initialize the variable 'm1' to silence this warning
                        double m0, m1;
                                     ^
                                      = 0.0
censoring.cpp:60:15: warning: variable 'use_d' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:66:21: note: uninitialized use occurs here
                        const double v = use_d ? d : c;
                                         ^~~~~
censoring.cpp:60:11: note: remove the 'if' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:60:15: warning: variable 'use_d' is used uninitialized whenever '&&' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~
censoring.cpp:66:21: note: uninitialized use occurs here
                        const double v = use_d ? d : c;
                                         ^~~~~
censoring.cpp:60:15: note: remove the '&&' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~
censoring.cpp:18:12: note: initialize the variable 'use_d' to silence this warning
        bool use_d;
                  ^
                   = false
23 warnings generated.
clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Rcpp/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/grDevices/include' -I/usr/local/include  -ggdb -fPIC  -Wall -g -O2  -c utils.cpp -o utils.o
clang++ -mmacosx-version-min=10.13 -std=gnu++11 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/usr/local/lib -o destiny.so RcppExports.o censoring.o utils.o -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation
installing to /Library/Frameworks/R.framework/Versions/4.0/Resources/library/00LOCK-destiny/00new/destiny/libs
** R
** data
** demo
** inst
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** installing vignettes
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (destiny)

The downloaded source packages are in
    ‘/private/var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T/RtmpXGhNV1/downloaded_packages’
Old packages: 'ape', 'backports', 'callr', 'car', 'ComplexHeatmap',
  'conquer', 'cowplot', 'data.table', 'deldir', 'devtools', 'dplyr',
  'DT', 'fields', 'fs', 'glue', 'Hmisc', 'jsonlite', 'lmtest',
  'maptools', 'MASS', 'mgcv', 'nlme', 'pbapply', 'processx', 'ps',
  'quantreg', 'RcppArmadillo', 'RcppHNSW', 'remotes', 'renv', 'Seurat',
  'sf', 'shape', 'stringi', 'sys', 'tidyr', 'vctrs', 'xfun', 'zip'
Update all/some/none? [a/s/n]: 
Loading required package: destiny

Attaching package: ‘destiny’

The following object is masked from ‘package:SummarizedExperiment’:

    distance

The following object is masked from ‘package:GenomicRanges’:

    distance

The following object is masked from ‘package:IRanges’:

    distance
[1] "destiny installed and loaded"

load data

## load sex only branch cells saved from GCSKO_Sex_Branch_Analysis.Rmd
## Restore the objects
## load sex branch dataset
tenx.mutant.integrated.sex <- readRDS("../data_to_export/tenx.mutant.integrated.sex.RDS")
## load full dataset
#tenx.mutant.integrated <- readRDS("../data_to_export/tenx.mutant.integrated.RDS")
## add old pt values
## these values are calculated in hte GCSKO_pseudotime_allcells.Rmd script and so were added after the object was split into sex only.
tenx.all <- readRDS("../data_to_export/tenx.mutant.integrated.RDS")
tenx.all.meta <- as.data.frame(tenx.all@meta.data)
tenx.all.meta <- tenx.all.meta[which(rownames(tenx.all.meta) %in% rownames(tenx.mutant.integrated.sex@meta.data)),]
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, tenx.all.meta$old_pt_values, col.name = "old_pt_values")
## then remove these objects so they don't use up memory
rm(c(tenx.all, tenx.all.meta))
Error in rm(c(tenx.all, tenx.all.meta)) : 
  ... must contain names or character strings
## create a list of our mutant gene IDs
list_of_mutant_genes <- c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")

3. Dimensionalty Reduction

We will now re-calculate the UMAP, PCA and diffusion map to visualise the data since the old visualisation used the variation in the whole dataset and so some of the variation in this set of cells was obscured.

ref: https://github.com/satijalab/seurat/issues/1883

A. Recalculate PCA

The PCA is used as the basis of other dimensionality reductions so we will now recalculate this to get to our final UMAP.

First, run PCA again

tenx.mutant.integrated.sex <- RunPCA(tenx.mutant.integrated.sex, npcs = 30, verbose = FALSE)

Then inspect the PCs

ElbowPlot(tenx.mutant.integrated.sex, ndims = 30, reduction = "pca")

Have a quick look at the output

FeaturePlot(tenx.mutant.integrated.sex, reduction = "pca", pt.size = 0.01, features = "old_pt_values")

B. UMAP

calculate UMAP

check markers to orientate

plots <- FeaturePlot(tenx.mutant.integrated.sex, features = c("PBANKA-1319500", "PBANKA-0416100"), blend = TRUE, combine = FALSE, coord.fixed = TRUE, reduction = "umapoptimised_post_repca")

plots[[3]] + NoLegend()  # Get just the co-expression plot, built-in legend is meaningless for this plot

plots[[4]] # Get just the key

CombinePlots(plots[3:4], legend = 'none', ncol =2, nrow = 1, rel_widths = c(2, 1), rel_heights = c(4,1)) # Stitch the co-expression and key plots together
CombinePlots is being deprecated. Plots should now be combined using the patchwork system.

inspect mutants in 13 that are in between sexes

mutant_sex_cells <- rownames(tenx.mutant.integrated.sex[which(tenx.mutant.integrated.sex$genotype_combined == "Mutant"),])
Keys should be one or more alphanumeric characters followed by an underscore, setting key from umapoptimised_post_repca_ to umapoptimisedpostrepca_

4. Clustering

Investigate sub clustering of pre-branch clusters

Ultimately, we are looking for coexpression after the expression of AP2G:

## plot
marker_gene_plot_AP2G <- FeaturePlot(tenx.mutant.integrated.sex, features = "PBANKA-1437500", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP", pt.size = 1, order = TRUE) + 
  theme_void() + 
  labs(title = paste("AP2G Expression")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold")) + 
  scale_colour_gradientn(colours=c("#DCDCDC", plasma(30)))
Scale for 'colour' is already present. Adding another scale for
'colour', which will replace the existing scale.
##view
marker_gene_plot_AP2G

and we have the following clusters currently:

## Plot
umap_cluster <- DimPlot(tenx.mutant.integrated.sex, label = TRUE, label.size = 8, repel = FALSE, pt.size = 0.5, dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() +
  theme(legend.position="bottom", 
        axis.line=element_blank(),
        axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks=element_blank(),
        axis.title.x=element_blank(),
        axis.title.y=element_blank()) + 
  guides(colour=guide_legend(nrow = 3, byrow = TRUE, override.aes = list(size=5)))

## print
umap_cluster

13 is the common sex branch so we will interrogate that branch

## subset cluster 13 cells
cells_thirteen <- rownames(tenx.mutant.integrated.sex@meta.data[tenx.mutant.integrated.sex@meta.data$seurat_clusters == 13, ])

## subset cluster 13
seurat_thirteen <- subset(tenx.mutant.integrated.sex, cells = cells_thirteen)
Keys should be one or more alphanumeric characters followed by an underscore, setting key from umapoptimised_post_repca_ to umapoptimisedpostrepca_
## re-PCA
seurat_thirteen <- RunPCA(seurat_thirteen, npcs = 30, verbose = FALSE)
ElbowPlot(seurat_thirteen, ndims = 30, reduction = "pca")


## recluster
seurat_thirteen <- FindNeighbors(seurat_thirteen, dims = 1:15)
Computing nearest neighbor graph
Computing SNN
seurat_thirteen <- FindClusters(seurat_thirteen, resolution = 1, random.seed = 42, algorithm = 2)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 222
Number of edges: 10912

Running Louvain algorithm with multilevel refinement...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.3347
Number of communities: 3
Elapsed time: 0 seconds
## plot cluster resolution = 1
## plot
DimPlot(seurat_thirteen, reduction = "DIM_UMAP",  dims = c(2,1), label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.1") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

2 and 1 are superimposed on the branch, lets find markers for each cluster

markers_subset <- seurat_thirteen_markers %>% group_by(cluster) %>% top_n(n = 50, wt = avg_logFC) %>% filter(p_val_adj < 0.05)
markers_subset


## find markers
markers_subset_mutant <- markers_subset[which(markers_subset$gene %in% list_of_mutant_genes), ]
markers_subset_mutant

## plot
VlnPlot(seurat_thirteen, features = c(markers_subset_mutant$gene, "PBANKA-1437500"), assay = "RNA")

Specifically look for markers between 1 and 2

Just check that mutants aren’t interfering with the analysis i.e. the clusters don’t just belong to a certain genotype or mutant cell

table(seurat_thirteen$seurat_clusters, seurat_thirteen$identity_combined)
   
    GCSKO-28 GCSKO-3 WT WT_10X
  0        0       3  1     72
  1        2       4  1     69
  2        0       6  0     64

Do the same analysis on cluster 3 quickly

## find markers
cells_three_markers <- FindAllMarkers(cells_three, only.pos = FALSE, min.pct = 0.25, logfc.threshold = 0.25)
Calculating cluster 0

  |                                                  | 0 % ~calculating  
  |++                                                | 2 % ~00s          
  |+++                                               | 5 % ~00s          
  |++++                                              | 7 % ~00s          
  |+++++                                             | 10% ~00s          
  |++++++                                            | 12% ~00s          
  |++++++++                                          | 14% ~00s          
  |+++++++++                                         | 17% ~00s          
  |++++++++++                                        | 19% ~00s          
  |+++++++++++                                       | 21% ~00s          
  |++++++++++++                                      | 24% ~00s          
  |++++++++++++++                                    | 26% ~00s          
  |+++++++++++++++                                   | 29% ~00s          
  |++++++++++++++++                                  | 31% ~00s          
  |+++++++++++++++++                                 | 33% ~00s          
  |++++++++++++++++++                                | 36% ~00s          
  |++++++++++++++++++++                              | 38% ~00s          
  |+++++++++++++++++++++                             | 40% ~00s          
  |++++++++++++++++++++++                            | 43% ~00s          
  |+++++++++++++++++++++++                           | 45% ~00s          
  |++++++++++++++++++++++++                          | 48% ~00s          
  |+++++++++++++++++++++++++                         | 50% ~00s          
  |+++++++++++++++++++++++++++                       | 52% ~00s          
  |++++++++++++++++++++++++++++                      | 55% ~00s          
  |+++++++++++++++++++++++++++++                     | 57% ~00s          
  |++++++++++++++++++++++++++++++                    | 60% ~00s          
  |+++++++++++++++++++++++++++++++                   | 62% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 64% ~00s          
  |++++++++++++++++++++++++++++++++++                | 67% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 69% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 74% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 76% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 79% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 86% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 88% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 90% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 93% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
Calculating cluster 1

  |                                                  | 0 % ~calculating  
  |+                                                 | 2 % ~00s          
  |++                                                | 3 % ~00s          
  |+++                                               | 5 % ~00s          
  |++++                                              | 6 % ~00s          
  |+++++                                             | 8 % ~00s          
  |+++++                                             | 10% ~00s          
  |++++++                                            | 11% ~00s          
  |+++++++                                           | 13% ~00s          
  |++++++++                                          | 15% ~00s          
  |+++++++++                                         | 16% ~01s          
  |+++++++++                                         | 18% ~01s          
  |++++++++++                                        | 19% ~00s          
  |+++++++++++                                       | 21% ~01s          
  |++++++++++++                                      | 23% ~00s          
  |+++++++++++++                                     | 24% ~01s          
  |+++++++++++++                                     | 26% ~00s          
  |++++++++++++++                                    | 27% ~00s          
  |+++++++++++++++                                   | 29% ~00s          
  |++++++++++++++++                                  | 31% ~00s          
  |+++++++++++++++++                                 | 32% ~00s          
  |+++++++++++++++++                                 | 34% ~00s          
  |++++++++++++++++++                                | 35% ~00s          
  |+++++++++++++++++++                               | 37% ~00s          
  |++++++++++++++++++++                              | 39% ~00s          
  |+++++++++++++++++++++                             | 40% ~00s          
  |+++++++++++++++++++++                             | 42% ~00s          
  |++++++++++++++++++++++                            | 44% ~00s          
  |+++++++++++++++++++++++                           | 45% ~00s          
  |++++++++++++++++++++++++                          | 47% ~00s          
  |+++++++++++++++++++++++++                         | 48% ~00s          
  |+++++++++++++++++++++++++                         | 50% ~00s          
  |++++++++++++++++++++++++++                        | 52% ~00s          
  |+++++++++++++++++++++++++++                       | 53% ~00s          
  |++++++++++++++++++++++++++++                      | 55% ~00s          
  |+++++++++++++++++++++++++++++                     | 56% ~00s          
  |++++++++++++++++++++++++++++++                    | 58% ~00s          
  |++++++++++++++++++++++++++++++                    | 60% ~00s          
  |+++++++++++++++++++++++++++++++                   | 61% ~00s          
  |++++++++++++++++++++++++++++++++                  | 63% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~00s          
  |++++++++++++++++++++++++++++++++++                | 66% ~00s          
  |++++++++++++++++++++++++++++++++++                | 68% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 69% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 74% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 76% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 79% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 82% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 90% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 92% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 98% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=01s  
Calculating cluster 2

  |                                                  | 0 % ~calculating  
  |+                                                 | 1 % ~01s          
  |++                                                | 3 % ~01s          
  |++                                                | 4 % ~01s          
  |+++                                               | 5 % ~01s          
  |++++                                              | 6 % ~01s          
  |++++                                              | 8 % ~01s          
  |+++++                                             | 9 % ~01s          
  |++++++                                            | 10% ~01s          
  |++++++                                            | 11% ~01s          
  |+++++++                                           | 13% ~01s          
  |+++++++                                           | 14% ~01s          
  |++++++++                                          | 15% ~01s          
  |+++++++++                                         | 16% ~01s          
  |+++++++++                                         | 18% ~01s          
  |++++++++++                                        | 19% ~01s          
  |+++++++++++                                       | 20% ~01s          
  |+++++++++++                                       | 22% ~01s          
  |++++++++++++                                      | 23% ~01s          
  |+++++++++++++                                     | 24% ~01s          
  |+++++++++++++                                     | 25% ~01s          
  |++++++++++++++                                    | 27% ~01s          
  |++++++++++++++                                    | 28% ~01s          
  |+++++++++++++++                                   | 29% ~01s          
  |++++++++++++++++                                  | 30% ~01s          
  |++++++++++++++++                                  | 32% ~01s          
  |+++++++++++++++++                                 | 33% ~01s          
  |++++++++++++++++++                                | 34% ~01s          
  |++++++++++++++++++                                | 35% ~01s          
  |+++++++++++++++++++                               | 37% ~01s          
  |+++++++++++++++++++                               | 38% ~01s          
  |++++++++++++++++++++                              | 39% ~01s          
  |+++++++++++++++++++++                             | 41% ~01s          
  |+++++++++++++++++++++                             | 42% ~01s          
  |++++++++++++++++++++++                            | 43% ~01s          
  |+++++++++++++++++++++++                           | 44% ~01s          
  |+++++++++++++++++++++++                           | 46% ~01s          
  |++++++++++++++++++++++++                          | 47% ~01s          
  |+++++++++++++++++++++++++                         | 48% ~01s          
  |+++++++++++++++++++++++++                         | 49% ~01s          
  |++++++++++++++++++++++++++                        | 51% ~01s          
  |++++++++++++++++++++++++++                        | 52% ~01s          
  |+++++++++++++++++++++++++++                       | 53% ~01s          
  |++++++++++++++++++++++++++++                      | 54% ~01s          
  |++++++++++++++++++++++++++++                      | 56% ~01s          
  |+++++++++++++++++++++++++++++                     | 57% ~01s          
  |++++++++++++++++++++++++++++++                    | 58% ~01s          
  |++++++++++++++++++++++++++++++                    | 59% ~01s          
  |+++++++++++++++++++++++++++++++                   | 61% ~01s          
  |++++++++++++++++++++++++++++++++                  | 62% ~01s          
  |++++++++++++++++++++++++++++++++                  | 63% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 66% ~00s          
  |++++++++++++++++++++++++++++++++++                | 67% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 70% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 72% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 76% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 78% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 80% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 82% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 90% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 92% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 96% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=01s  
Calculating cluster 3

  |                                                  | 0 % ~calculating  
  |+                                                 | 1 % ~01s          
  |++                                                | 2 % ~01s          
  |++                                                | 3 % ~01s          
  |+++                                               | 4 % ~01s          
  |+++                                               | 5 % ~01s          
  |++++                                              | 7 % ~01s          
  |++++                                              | 8 % ~01s          
  |+++++                                             | 9 % ~01s          
  |+++++                                             | 10% ~01s          
  |++++++                                            | 11% ~01s          
  |++++++                                            | 12% ~01s          
  |+++++++                                           | 13% ~01s          
  |++++++++                                          | 14% ~01s          
  |++++++++                                          | 15% ~01s          
  |+++++++++                                         | 16% ~01s          
  |+++++++++                                         | 17% ~01s          
  |++++++++++                                        | 18% ~01s          
  |++++++++++                                        | 20% ~01s          
  |+++++++++++                                       | 21% ~01s          
  |+++++++++++                                       | 22% ~01s          
  |++++++++++++                                      | 23% ~01s          
  |++++++++++++                                      | 24% ~01s          
  |+++++++++++++                                     | 25% ~01s          
  |++++++++++++++                                    | 26% ~01s          
  |++++++++++++++                                    | 27% ~01s          
  |+++++++++++++++                                   | 28% ~01s          
  |+++++++++++++++                                   | 29% ~01s          
  |++++++++++++++++                                  | 30% ~01s          
  |++++++++++++++++                                  | 32% ~01s          
  |+++++++++++++++++                                 | 33% ~01s          
  |+++++++++++++++++                                 | 34% ~01s          
  |++++++++++++++++++                                | 35% ~01s          
  |++++++++++++++++++                                | 36% ~01s          
  |+++++++++++++++++++                               | 37% ~01s          
  |++++++++++++++++++++                              | 38% ~01s          
  |++++++++++++++++++++                              | 39% ~01s          
  |+++++++++++++++++++++                             | 40% ~01s          
  |+++++++++++++++++++++                             | 41% ~01s          
  |++++++++++++++++++++++                            | 42% ~01s          
  |++++++++++++++++++++++                            | 43% ~01s          
  |+++++++++++++++++++++++                           | 45% ~01s          
  |+++++++++++++++++++++++                           | 46% ~01s          
  |++++++++++++++++++++++++                          | 47% ~01s          
  |++++++++++++++++++++++++                          | 48% ~01s          
  |+++++++++++++++++++++++++                         | 49% ~01s          
  |+++++++++++++++++++++++++                         | 50% ~01s          
  |++++++++++++++++++++++++++                        | 51% ~01s          
  |+++++++++++++++++++++++++++                       | 52% ~01s          
  |+++++++++++++++++++++++++++                       | 53% ~01s          
  |++++++++++++++++++++++++++++                      | 54% ~01s          
  |++++++++++++++++++++++++++++                      | 55% ~01s          
  |+++++++++++++++++++++++++++++                     | 57% ~01s          
  |+++++++++++++++++++++++++++++                     | 58% ~01s          
  |++++++++++++++++++++++++++++++                    | 59% ~01s          
  |++++++++++++++++++++++++++++++                    | 60% ~01s          
  |+++++++++++++++++++++++++++++++                   | 61% ~01s          
  |+++++++++++++++++++++++++++++++                   | 62% ~01s          
  |++++++++++++++++++++++++++++++++                  | 63% ~01s          
  |+++++++++++++++++++++++++++++++++                 | 64% ~01s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~01s          
  |++++++++++++++++++++++++++++++++++                | 66% ~01s          
  |++++++++++++++++++++++++++++++++++                | 67% ~01s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~01s          
  |+++++++++++++++++++++++++++++++++++               | 70% ~01s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~01s          
  |++++++++++++++++++++++++++++++++++++              | 72% ~01s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 74% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 76% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 78% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 79% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 80% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 82% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 86% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 88% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 90% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 92% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 93% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=02s  
## inspect result
markers_subset <- cells_three_markers %>% group_by(cluster) %>% top_n(n = 50, wt = avg_logFC) %>% filter(p_val_adj < 0.05)
markers_subset

## find markers
markers_subset_mutant <- markers_subset[which(markers_subset$gene %in% list_of_mutant_genes), ]
markers_subset_mutant

## plot
VlnPlot(cells_three, features = c(markers_subset_mutant$gene, "PBANKA-1437500"), assay = "RNA")

df_plot <- data.frame(t(data.frame(cells_three@assays$RNA[c("PBANKA-1447900", "PBANKA-1437500"), ])))

ggplot(df_plot, aes(PBANKA.1447900, PBANKA.1437500)) + geom_point()

6. Monocle on sex cells

calculate pseudotime and modules

Preparation

## extracts only 10x cells and also remove cluster 0 cells 
wt_cells <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X" & !tenx.mutant.integrated.sex@meta.data$seurat_clusters == "0"),])

## make a new Seurat of this
seurat.object <-subset(tenx.mutant.integrated.sex, cells = wt_cells)
Keys should be one or more alphanumeric characters followed by an underscore, setting key from umapoptimised_post_repca_ to umapoptimisedpostrepca_
## check that this is the same as the pb_sex_filtered object
#data_test <- as(as.matrix(GetAssayData(pb_sex_filtered, assay = "RNA", slot = "data")), 'sparseMatrix')
#is.equal
#is.identical

## extract counts and pheno:
## the reason we use the integrated and then subsetted is because these cells have been normalised whereas the cells in pb_sex_filtered have not been normalised (well they have but with doublets in them)
data <- as(as.matrix(GetAssayData(seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
## make phenodata
pd <- data.frame(seurat.object@meta.data)
## keep only the columns that are relevant in metadata
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
## make gene metadata
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))

## Construct monocle cds
monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)

## preprocess
monocle.object = preprocess_cds(monocle.object, num_dim = 50, norm_method = "none")
### if using integrated data:
# norm_method = "none", alignment_group = "~ experiment"

## plot jack straw plot
#plot_pc_variance_explained(monocle.object)

#monocle.object = reduce_dimension(monocle.object, reduction_method = "UMAP", preprocess_method = "PCA", umap.metric = "euclidean", umap.n_neighbors = 50, umap.min_dist = 0.5, verbose = FALSE)

#plot_cells(monocle.object, color_cells_by="experiment")

## graph learning

## add UMAP from Seurat
monocle.object@int_colData@listData$reducedDims@listData[["UMAP"]] <- seurat.object@reductions[["DIM_UMAP"]]@cell.embeddings

## cluster
## this is essential to run the learn_graph function later on
monocle.object = cluster_cells(monocle.object)

## plot initial clustering by monocle
#plot_cells(monocle.object, color_cells_by="cluster", group_cells_by="partition", x = 2, y = 1)

## map pseudotime
monocle.object = learn_graph(monocle.object, learn_graph_control=list(ncenter=500), use_partition = FALSE)

  |                                                                    
  |                                                              |   0%
  |                                                                    
  |==============================================================| 100%
# learn_graph_control=list(ncenter=500) - play with this parameter

## Plot cells
plot_cells(monocle.object, color_cells_by="partition", group_cells_by="partition", x = 2, y = 1)
Cells aren't colored in a way that allows them to be grouped.

Pseudotime Calculation

save

ggsave("../images_to_export/GCSKO_sexbranch_umap_pt.png", plot = umap_pt, device = "png", path = NULL, scale = 1, width = 10, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

Just check if the ‘hook’ on the males is a lineage or dead/dying/activated gams, or mutants

FeaturePlot(tenx.mutant.integrated.sex, features = "PBANKA-0416100", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP", pt.size = 1, order = TRUE) + 
            theme_void() + 
            labs(title = paste("MG1 (Male)")) + 
            theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold")) + 
            scale_colour_gradientn(colours=c("#DCDCDC", plasma(30)))
Scale for 'colour' is already present. Adding another scale for
'colour', which will replace the existing scale.

It appears MG1 marker expression is decreasing/off in these cells - inspect mutant status

plot <- DimPlot(tenx.mutant.integrated.sex, label = FALSE, label.size = 8, repel = FALSE, pt.size = 0.05, dims = c(2,1), reduction = "DIM_UMAP", group.by = "identity_updated") + 
  coord_fixed() +
  theme(legend.position="bottom", 
        axis.line=element_blank(),
        axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks=element_blank(),
        axis.title.x=element_blank(),
        axis.title.y=element_blank()) + 
  guides(colour=guide_legend(nrow = 3, byrow = TRUE, override.aes = list(size=5)))

HoverLocator(plot = plot, information = FetchData(tenx.mutant.integrated.sex, vars = c("ident", "identity_updated", "nFeature_RNA")))
the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used`error_y.color` does not currently support multiple values.`error_x.color` does not currently support multiple values.`line.color` does not currently support multiple values.The titlefont attribute is deprecated. Use title = list(font = ...) instead.the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used`error_y.color` does not currently support multiple values.`error_x.color` does not currently support multiple values.`line.color` does not currently support multiple values.The titlefont attribute is deprecated. Use title = list(font = ...) instead.

Check how well it correlates with the original pseudotime

when pseudotime was calcualted on the whole object

library(ggpubr)
## extract pseudotime values:
pt_values_new <- as.data.frame(pseudotime(monocle.object, reduction_method = "UMAP"))
pt_values_new$cell_name <- rownames(pt_values_new)
meta_data_df <- as.data.frame(monocle.object@colData)
meta_data_df$cell_name <- rownames(meta_data_df)
meta_data_df <- merge(meta_data_df, pt_values_new, by = "cell_name")
names(meta_data_df)[ncol(meta_data_df)]<- "pt"

ggplot(meta_data_df, aes(x = old_pt_values, y = pt, colour = cluster_colours_figure)) + 
  geom_point() +  
  geom_smooth(method = "lm", se = FALSE) +
  theme_classic() + stat_cor(method = "pearson")

This shows very good correlation, and the females have a slightly different correlation but we can see that the branches fit well on the UMAP.

Isolate Branches

## access the closest principal graph node vertex for each cell and assign it as a column in your colData table using
colData(monocle.object)$closest_vertex <- monocle.object@principal_graph_aux[["UMAP"]]$pr_graph_cell_proj_closest_vertex[,1]

## plot
plot_cells(monocle.object, color_cells_by = "closest_vertex", label_cell_groups = FALSE)

Module Construction

gene_module_df_sex <- find_gene_modules(monocle.object[pr_deg_ids,], resolution=c(10^seq(-6,2)), random_seed = 1234)
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
## how many genes in modules?
dim(gene_module_df_sex)
[1] 3260    5
[1] "there are 16 modules"

Plot Modules

General Module Composition

Make a dataframe to plot by aggregating clusters vs. modules

## make cell group df
cell_group_df <- tibble::tibble(cell=row.names(colData(monocle.object)), cell_group=colData(monocle.object)$seurat_clusters)

## make plotting df
agg_mat <- aggregate_gene_expression(monocle.object, gene_module_df_sex, cell_group_df)

Find out how many genes there are per total so we can add this to the plot

## how many genes per module?
genes_per_module <- as.data.frame(table(gene_module_df_sex$module))
genes_per_module

Find out which modules our mutant genes reside in

## create a list of our mutant gene IDs
list_of_mutant_genes <- c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")

## make a dataframe to convert the gene IDs into actual IDs
df_mutant_ids <- as.data.frame(unique(cbind(tenx.mutant.integrated@meta.data$identity_gene_updated, tenx.mutant.integrated@meta.data$identity_updated)))[-c(1, 3),]
# remove the "820" bit on 10
df_mutant_ids$V1 <- gsub("_820", "", df_mutant_ids$V1)
# change the underscore (_) to a dash (-) in gene IDs
df_mutant_ids$V1 <- gsub("_", "-", df_mutant_ids$V1)
names(df_mutant_ids) <- c("gene_ID", "mutant_identity")

## subset modules df to include only mutant gene IDs
df_mutant_gene_modules <- as.data.frame(gene_module_df_sex[which(gene_module_df_sex$id %in% list_of_mutant_genes),])
names(df_mutant_gene_modules)[1] <- "gene_ID"

## merge dataframes
df_mutant_gene_modules <- merge(df_mutant_gene_modules, df_mutant_ids, by = "gene_ID")

## Inspect
df_mutant_gene_modules

so modules of interest are:

table(df_mutant_gene_modules$module)

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 
 4  0  0  0  0  0  0  0  0  2  2  1  0  0  1  0  0  0 

Which modules do other genes of interest lie in?:

## landmark genes (genes of interest)
# AP2G - PBANKA-1437500
# AP2 - PBANKA-0909600 - from poran paper
# AP2G-2 - PBANKA-1034300 
# ccp2 - "PBANKA-1319500" - female 820
# p25 - "PBANKA-0515000" - female
# p28 - "PBANKA-0514900" - female
# ccp3 - "PBANKA-1035200" - female -  https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5909122/
# nek4 - "PBANKA-0616700" - female
# ap2-fg - "PBANKA-1415700" - female 
# dozi - "PBANKA-1217700" - female
# MG1 - "PBANKA-0416100" - male 820
# hap2 - "PBANKA-1212600" - male
# MAPK2 - "PBANKA-0933700" - male
# nek1 - "PBANKA-1443000" - male
# cdpk4 - "PBANKA-0615200" - male

## create a list of landmark genes
list_of_landmark_genes <- c("PBANKA-1437500",
                            "PBANKA-0909600",
                            "PBANKA-1034300", 
                            "PBANKA-1319500", 
                            "PBANKA-0515000",
                            "PBANKA-0514900",
                            "PBANKA-1035200",
                            "PBANKA-0616700",
                            "PBANKA-1415700",
                            "PBANKA-1217700",
                            "PBANKA-0416100", 
                            "PBANKA-1212600",
                            "PBANKA-0933700",
                            "PBANKA-1443000",
                            "PBANKA-0615200")

name_of_landmark_genes <- c("AP2-G", 
                            "AP2_poran", 
                            "AP2-G2", 
                            "ccp2", 
                            "p25", 
                            "p28",
                            "ccp3",
                            "nek4",
                            "ap2-fg",
                            "DOZI",
                            "mg1", 
                            "hap2", 
                            "mapk2",
                            "nek1",
                            "cdpk4")

## make a df
name_of_landmark_genes <- data.frame("gene_name" = name_of_landmark_genes, "id" = list_of_landmark_genes)

## make dataframe
df_landmark_gene_modules <- gene_module_df_sex[which(gene_module_df_sex$id %in% list_of_landmark_genes),]

## merge dataframes
df_landmark_gene_modules <- merge(df_landmark_gene_modules, name_of_landmark_genes, by = "id")

## inspect
df_landmark_gene_modules

enrichment of screen hits in modules

DOZI-regulated genes

Find out how many of the genes in each module has a DOZI-regulated gene

DOZI_regulated_genes <-
read.csv(file = "../data/Reference/DOZI_regulated_genes.csv", header = TRUE)

## extract gene IDs
dozi_genes <- DOZI_regulated_genes[DOZI_regulated_genes$DOZI_regulated. == "YES", ]$Gene_ID_PB
## change the underscore to a dash
dozi_genes <- gsub("_", "-", dozi_genes)

## find out which modules they are in
df_dozi_gene_modules <- gene_module_df_sex[which(gene_module_df_sex$id %in% dozi_genes),]
print("dozi genes by module")
[1] "dozi genes by module"
table(df_dozi_gene_modules$module)

  8   7   6   3  12  15   4  16   1   2  18  13  17   5   9  14  10  11 
  4   7  10  10   6   5  11   6  10 122  23  10   8   2   2   0   9   4 

Visualise module expression

plot out modules

UMAP_modules <- plot_cells(monocle.object, genes=gene_module_df_sex %>% filter(module %in% c(1:20)),
           cell_size = 2, 
           x = 2, y = 1,
           label_cell_groups=FALSE,
           scale_to_range = TRUE,
           show_trajectory_graph=FALSE) +
                          scale_colour_viridis_c(name = "expression", option = "C", alpha = 1) +
                          coord_fixed() +
                          theme_void() +
                          theme(legend.position = "bottom", strip.text.x = element_text(size = 15))
Scale for 'colour' is already present. Adding another scale for
'colour', which will replace the existing scale.

## view
UMAP_modules

save

ggsave("../images_to_export/GCSKO_sexbranch_umap_modules.png", plot = UMAP_modules, device = "png", path = NULL, scale = 1, width = 30, height = 30, units = "cm", dpi = 300, limitsize = TRUE)
## make a dataframe of genes per module
genes_per_module <- as.data.frame(table(gene_module_df_sex$module))

## inspect
genes_per_module

save

ggsave("../images_to_export/GCSKO_sexbranch_heatmap.png", plot = heatmap_main, device = "png", path = NULL, scale = 1, width = 27, height = 20, units = "cm", dpi = 300, limitsize = TRUE)

Visualise the expression of select genes over pseudotime

## landmark genes (genes of interest)
# AP2G - PBANKA-1437500
# AP2 - PBANKA-0909600 - from poran paper
# AP2G-2 - PBANKA-1034300 
#list_of_mutant_genes <- c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")

## define genes to plot
list_of_genes_of_interest <- c("PBANKA-0102400", "PBANKA-0413400", "PBANKA-0716500", "PBANKA-0828000", "PBANKA-0902300", "PBANKA-1144800", "PBANKA-1302700", "PBANKA-1418100", "PBANKA-1435200", "PBANKA-1447900", "PBANKA-1454800", "PBANKA-1437500", "PBANKA-1319500", "PBANKA-0416100", "PBANKA-1034300")
## add names
names_of_genes_of_interest <- c("GCSKO-2", "GCSKO-10", "GCSKO-19", "GCSKO-3", "GCSKO-13", "GCSKO-28", "GCSKO-oom", "GCSKO-17", "GCSKO-20", "GCSKO-29", "GCSKO-21", "AP2-G", "CCP2", "MG1", "AP2-G2")

##make df for genes of interest
genes_of_interest <- data.frame(gene = list_of_genes_of_interest, group = c(1:length(list_of_genes_of_interest)), name = names_of_genes_of_interest)
## reorder
#genes_of_interest <- genes_of_interest[match(c("AP2-G", "CCP2", "GCSKO-21", "GCSKO-17", "GCSKO-2", "MG1", "GCSKO-20", "GCSKO-3", "GCSKO-oom", "GCSKO-29", "GCSKO-10", "GCSKO-28", "GCSKO-19", "GCSKO-13"), genes_of_interest$name), ]

## prepare custom dataframe for all cells by modules:
agg_mat_genes_of_interest <- aggregate_gene_expression(monocle.object, genes_of_interest[,1:2])

## reorder using new order
agg_mat_genes_of_interest <- agg_mat_genes_of_interest[,col.order]

## plot
heatmap_plot <- pheatmap::pheatmap(agg_mat_genes_of_interest, 
                   #scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = TRUE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   labels_row = as.character(genes_of_interest[,3]),
                   gaps_col = c(length(asex_cells), length(c(asex_cells,bi_cells)), length(c(asex_cells,bi_cells,female_cells))),
                   #gaps_row = c(1, 6),
                   cutree_rows = 2,
                   ## trying to fix legend issue here
                   #fontsize_row = 10,
                   #fontsize_col = 3,
                   #cellheight=3, 
                   #cellwidth = 3,
                   legend = TRUE,
                   annotation_legend = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours
                   )

heatmap_plot

look at some of the “module” genes now too

## landmark genes (genes of interest)
# AP2G - PBANKA-1437500
# AP2 - PBANKA-0909600 - from poran paper
# AP2G-2 - PBANKA-1034300 
#list_of_mutant_genes <- c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")

## define genes to plot
list_of_genes_of_interest <- c("PBANKA-1454000", "PBANKA-1354000")
## add names
names_of_genes_of_interest <- c("GyrB", "DBR1")

##make df for genes of interest
genes_of_interest <- data.frame(gene = list_of_genes_of_interest, group = c(1:length(list_of_genes_of_interest)), name = names_of_genes_of_interest)
## reorder
#genes_of_interest <- genes_of_interest[match(c("AP2-G", "CCP2", "GCSKO-21", "GCSKO-17", "GCSKO-2", "MG1", "GCSKO-20", "GCSKO-3", "GCSKO-oom", "GCSKO-29", "GCSKO-10", "GCSKO-28", "GCSKO-19", "GCSKO-13"), genes_of_interest$name), ]

## prepare custom dataframe for all cells by modules:
agg_mat_genes_of_interest <- aggregate_gene_expression(monocle.object, genes_of_interest[,1:2])

## reorder using new order
agg_mat_genes_of_interest <- agg_mat_genes_of_interest[,col.order]

## plot
heatmap_plot <- pheatmap::pheatmap(agg_mat_genes_of_interest, 
                   #scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = TRUE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   labels_row = as.character(genes_of_interest[,3]),
                   gaps_col = c(length(asex_cells), length(c(asex_cells,bi_cells)), length(c(asex_cells,bi_cells,female_cells))),
                   #gaps_row = c(1, 6),
                   cutree_rows = 2,
                   ## trying to fix legend issue here
                   #fontsize_row = 10,
                   #fontsize_col = 3,
                   #cellheight=3, 
                   #cellwidth = 3,
                   legend = TRUE,
                   annotation_legend = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours
                   )

heatmap_plot

Make annotations to add to the heatmap

## change names for row names to include "module " at the begining of them
row.names(agg_mat) <- stringr::str_c("Module ", row.names(agg_mat))

## add number of cells to the rownames for the module
for(i in seq_along(genes_per_module$Freq)){
  row.names(agg_mat)[i] <- stringr::str_c(row.names(agg_mat)[i]," (n = " ,genes_per_module$Freq[i], ")")
}

## create annotation of clusters for pheatmap:
cluster_anno <- data.frame(cluster = unique(colData(monocle.object)$seurat_clusters))
row.names(cluster_anno) <- cluster_anno$cluster

## clusters were defined earlier as:
male_clusters <- c("13", "5", "11", "25", "1", "17", "10", "24", "14", "27", "19")
female_clusters <- c("16", "22", "23", "15", "21", "30", "4", "3", "18", "7", "8", "6", "20", "12", "26")
asex_clusters <- c("0", "9", "28", "2", "29")

## add identities to the column
cluster_anno$group <- NA
cluster_anno$group[which(cluster_anno$cluster %in% asex_clusters)] <- "Asexual"
cluster_anno$group[which(cluster_anno$cluster %in% male_clusters)] <- "Male"
cluster_anno$group[which(cluster_anno$cluster %in% female_clusters)] <- "Female"
cluster_anno <- cluster_anno[ , 2, drop = FALSE]
cluster_anno

## add median pseudotime per cluster
## help here:
## https://stackoverflow.com/questions/54360855/calculate-mean-for-column-grouped-by-values-of-two-other-columns
## make subsetted dataframe
df_median_pt <- meta_data_df[ ,c("pt", "seurat_clusters")]
## apply across dataframe to get median
mean.df1 <- tapply(df_median_pt$pt, list(df_median_pt$seurat_clusters), median)
mean.df2 <- as.data.frame(as.table(mean.df1))
names(mean.df2) <- c("seurat_clusters", "pt_Median")
rownames(mean.df2) <- mean.df2$seurat_clusters
## to make each value have the mean in the OG dataframe
#merge(df_median_pt, mean.df2)
## add to annotation dataframe
cluster_anno <- merge(cluster_anno, mean.df2, by=0)

## add rownames to dataframe
rownames(cluster_anno) <- cluster_anno$Row.names
## subset to have only info of interest
cluster_anno <- cluster_anno[,c(2,4)]
names(cluster_anno) <- c("Identity", "Median_Pseudotime_of_Cluster")

WT cells by modules over pt (central panel)

## make annotation colours
annotation_colours <- list(Identity = c(Male="#016c00", Female="#a52b1e", Asexual= "#0052c5"),
                           Median_Pseudotime_of_Cluster = magma(12, direction = 1))

## reorder the levels
## make df of data
agg_mat_df <- as.data.frame(agg_mat)
## remove levels in my_levels that are not present here - i.e. clusters that are missing because they are not represented in the 10X data
my_levels_10x_data <- my_levels_sex[which(my_levels_sex %in% colnames(agg_mat_df))]
## sort the values
agg_mat_df <- agg_mat_df[ ,(match(my_levels_10x_data, colnames(agg_mat_df)))]

## order 
#cluster_anno <- cluster_anno[(match(my_levels_10x_data, rownames(cluster_anno))), ]

## reorder columns 
## first, order the annotation
cluster_anno <- cluster_anno[with(cluster_anno, order(Identity, Median_Pseudotime_of_Cluster)),]

## remove the NAs from this
cluster_anno <- cluster_anno[complete.cases(cluster_anno),]

agg_mat_df <- agg_mat_df[ ,match(rownames(cluster_anno), colnames(agg_mat_df))]

## plot heatmap
pheatmap::pheatmap(agg_mat_df, 
                   scale="row",
                   cluster_cols = FALSE,
                   clustering_method="ward.D2", 
                   annotation_col = cluster_anno, 
                   annotation_colors = annotation_colours, 
                   cutree_rows = 12)

#, gaps_col = c(28,29,37)
#row.names(agg_mat) <- factor(row.names(agg_mat), levels = row.names(agg_mat)[module_dendro$order])

## plot heatmap
#pheatmap::pheatmap(agg_mat_df, 
  #                  scale="column",
  #                  cluster_cols = TRUE,
  #                  cluster_rows = module_dendro,
  #                  #clustering_method="ward.D2",
  #                  cutree_rows = 5,
  #                  annotation_col = cluster_anno, 
  #                  annotation_colors = annotation_colours) + 
  # theme(legend.position = "bottom")

All Cells

Plot specific genes of interest

Side plots

construct new dataframes for the cells from mutants for each sex

## The original object contains all cells, we just want wild-type so let's subset out gene_module_df and cell_group_df accordingly

## male
## subset out only male and pre determination cells
male_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$at_sex == "male"), ]
## take forward only smart-seq2
male_cells <- male_cells[which(male_cells$experiment == "mutants"), ]
## get cell names
male_cells <- rownames(male_cells)
## subset Seurat object to contain cells of interest  
male.seurat.object <- SubsetData(tenx.mutant.integrated.sex, cells = male_cells)
## make new counts and pheno:
data <- as(as.matrix(GetAssayData(male.seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(male.seurat.object@meta.data)
## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))
## Construct monocle cds
male.monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)
## preprocess
male.monocle.object = preprocess_cds(male.monocle.object, num_dim = 50, norm_method = "none")  
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
#male_cell_group_df <- data.frame(cell=as.character(factor(male_cell_group_df$cell_id)), cell_group=factor(male_cell_group_df$pt_bin))  
## aggregate expression
male_agg_mat <- aggregate_gene_expression(male.monocle.object, gene_module_df_sex, exclude.na = FALSE)

## female
## subset out only male and pre determination cells
female_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$at_sex == "female"), ]
## take forward only wild-type
female_cells <- female_cells[which(female_cells$experiment == "mutants"), ]
## get cell names
female_cells <- rownames(female_cells)
## subset our cell group df to keep only these cells
#female_cell_group_df <- female_cell_group_df[which(female_cell_group_df$cell_id %in% female_cells),]
## subset Seurat object to contain cells of interest  
female.seurat.object <- SubsetData(tenx.mutant.integrated.sex, cells = female_cells)
## make new counts and pheno:
data <- as(as.matrix(GetAssayData(female.seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(female.seurat.object@meta.data)
## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))
## Construct monocle cds
female.monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)
## preprocess
female.monocle.object = preprocess_cds(female.monocle.object, num_dim = 50, norm_method = "none")  
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
#female_cell_group_df <- data.frame(cell=as.character(factor(female_cell_group_df$cell_id)), cell_group=factor(female_cell_group_df$pt_bin))  
## aggregate expression
female_agg_mat <- aggregate_gene_expression(female.monocle.object, gene_module_df_sex, exclude.na = FALSE)

male

# male_agg_mat
## reorder using new order
male_agg_mat <- male_agg_mat[row.order, ]

## make an anotation
anno_male <- data.frame(male.monocle.object@colData$at_sex, male.monocle.object@colData$old_pt_values, genotype = male.monocle.object@colData$identity_updated, row.names = rownames(male.monocle.object@colData))
names(anno_male) <- c("sex", "Pseudotime", "genotype")

## make annotation colours
annotation_colours <- list(sex = c(male="#016c00", female="#a52b1e", 'pre-det' = "#0052c5"),
                           Pseudotime = magma(12, direction = 1))

## change the order of the data frame
col.order.male <- rownames(anno_male[with(anno_male, order(genotype, Pseudotime)), ])
male_agg_mat <- male_agg_mat[,col.order.male]

## plot
heatmap_male <- pheatmap::pheatmap(male_agg_mat, 
                   #scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   legend = FALSE,
                   annotation_legend = TRUE,
                   annotation_col = anno_male, 
                   annotation_colors = annotation_colours, 
                   cutree_rows = 12)

heatmap_male
# female_agg_mat
## reorder using new order
female_agg_mat <- female_agg_mat[row.order, ]

## make an anotation
anno_female <- data.frame(female.monocle.object@colData$at_sex, female.monocle.object@colData$old_pt_values, genotype = female.monocle.object@colData$identity_updated, row.names = rownames(female.monocle.object@colData))
names(anno_female) <- c("sex", "Pseudotime", "genotype")

## make annotation colours
annotation_colours <- list(sex = c(male="#016c00", female="#a52b1e", 'pre-det' = "#0052c5"),
                           Pseudotime = magma(12, direction = 1))

## change the order of the data frame
col.order.female <- rownames(anno_female[with(anno_female, order(genotype, Pseudotime)), ])
female_agg_mat <- female_agg_mat[,col.order.female]

## plot
heatmap_female <- pheatmap::pheatmap(female_agg_mat, 
                   #scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   legend = FALSE,
                   annotation_legend = FALSE,
                   annotation_col = anno_female, 
                   annotation_colors = annotation_colours, 
                   cutree_rows = 12)

heatmap_female

## save a pheatmap: https://stackoverflow.com/questions/43051525/how-to-draw-pheatmap-plot-to-screen-and-also-save-to-file

side plots with groups of mutant cells

female

## make a new grouping for cells based on their identity
mutant_group_female <- data.frame(cell = rownames(female.monocle.object@colData), cell_group = female.monocle.object@colData$identity_updated)

## aggregate expression
female_agg_mat_grouped <- aggregate_gene_expression(female.monocle.object, gene_module_df_sex, mutant_group_female, exclude.na = FALSE)

## reorder using new order
female_agg_mat_grouped <- female_agg_mat_grouped[row.order, ]

## plot
pheatmap::pheatmap(female_agg_mat_grouped, 
                   #scale="row",
                   cluster_cols = TRUE,
                   cluster_rows = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = TRUE,
                   legend = FALSE,
                   annotation_legend = FALSE,
                   #annotation_col = anno_female, 
                   #annotation_colors = annotation_colours, 
                   cutree_rows = 12)

male

module 12 inspection

## make a df for module 12 genes
module.12.genes <- gene_module_df_sex[gene_module_df_sex$module == 12, ]$id
module.12.genes <- data.frame(id = module.12.genes, group = module.12.genes)

## prepare custom dataframe for all cells by modules:
agg_mat_module_12 <- aggregate_gene_expression(monocle.object, module.12.genes)

## make an anotation
anno_no_group <- data.frame(monocle.object@colData$sex_UMAP, monocle.object@colData$old_pt_values, row.names = rownames(monocle.object@colData))
names(anno_no_group) <- c("sex", "Pseudotime")

## make annotation colours
annotation_colours <- list(sex = c(male="#016c00", female="#a52b1e", 'pre-det' = "#0052c5"),
                           Pseudotime = magma(12, direction = 1))

## change the order of the data frame
col.order <- c(pre_det_ordered_cells, female_ordered_cells, male_ordered_cells)
agg_mat_module_12 <- agg_mat_module_12[,col.order]

## plot
pheatmap::pheatmap(agg_mat_module_12, 
                   #scale="row",
                   cluster_cols = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours,
                   fontsize_row = 7,
                   cutree_rows = 12)

save plot

heatmap_module_12 <- pheatmap::pheatmap(agg_mat_module_12, 
                   #scale="row",
                   cluster_cols = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours,
                   fontsize_row = 7,
                   cutree_rows = 12)

AP2 Expression

## reading table of AP2 genes
ap2_genes_table <- read.delim(file = "~/data/AP2_genes_table.txt", header = TRUE, sep ="\t")

## extract list of genes
ap2_genes_list <- dplyr::pull(ap2_genes_table, Gene.ID)
ap2_genes_list <- gsub("_", "-", ap2_genes_list)

## make a df for genes
ap2_genes_list <- data.frame(id = ap2_genes_list, group = ap2_genes_list)

## prepare custom dataframe for all cells by modules:
agg_mat_ap2s <- aggregate_gene_expression(monocle.object, ap2_genes_list)

## change the order of the data frame
col.order <- c(pre_det_ordered_cells, female_ordered_cells, male_ordered_cells)
agg_mat_ap2s <- agg_mat_ap2s[,col.order]

## plot
pheatmap::pheatmap(agg_mat_ap2s, 
                   #scale="row",
                   cluster_cols = FALSE,
                   clustering_method="complete",
                   show_colnames = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours,
                   fontsize_row = 7,
                   cutree_rows = 3)

Module Analysis

Read in Kasia’s modules:

## read in kasia modules:
kasia_clusters <- read.csv(file = "~/data/Modules_Clusters_Phenotypes.csv", header = TRUE)

## change _ to -:
kasia_clusters$new.gene.ID <- gsub("_", "-", kasia_clusters$new.gene.ID)

## filter out genes not in modules gene_module_df_sex:
kasia_clusters_filtered <- kasia_clusters[which(kasia_clusters$new.gene.ID %in% gene_module_df_sex$id), ]

## rename new gene id
names(kasia_clusters_filtered)[2] <- "id"

## merge together
modules_merged_df <- merge(kasia_clusters_filtered, gene_module_df_sex, by = "id")

## look at the enrichment with a dotplot:
dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(modules_merged_df$Kasia.Cluster, df_meta_data$identity_combined), margin = 2)) * 100)

NOT USED complex heatmap version

## make into matrix to plot
col.order <- agg_mat_all_cells_matrix <- as.matrix(agg_mat_all_cells)

make annotation

## extract pseudotime values:
pt_values <- as.data.frame(pseudotime(monocle.object, reduction_method = "UMAP"))
names(pt_values) <- "monocle_pt_sex_wt"
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, pt_values)

## save pt values
write.csv(pt_values, file = "~/data_to_export/pt_values_sex_only.csv")
library(circlize)
## make the annotation df
## get meta data from seurat object and then subset rows out that are wt
df_anno <- tenx.mutant.integrated.sex@meta.data[which(rownames(tenx.mutant.integrated.sex@meta.data) %in% colnames(agg_mat_all_cells_matrix)), ]
## get only columns of interest:
df_anno <- df_anno[ ,c("sex", "monocle_pt_sex_wt"), drop = FALSE ]

## order annotation
df_anno <- df_anno[with(df_anno, order(sex, monocle_pt_sex_wt)),]

## order cols in the matrix
agg_mat_all_cells_matrix <- agg_mat_all_cells_matrix[ ,match(colnames(agg_mat_all_cells_matrix), rownames(df_anno))]

## make annotation
heatmap_annotation <- HeatmapAnnotation(df = cluster_anno, 
                                        col = list(sex = c(male="#016c00", female="#a52b1e", `pre-det` = "#0052c5"), monocle_pt_sex_wt = colorRamp2(c(1:70), inferno(70)))
                                        )

heatmap_annotation <- HeatmapAnnotation(sex = df_anno$sex, pt = df_anno$monocle_pt_sex_wt)

plot

## make heatmap
modules_heatmap <- Heatmap(agg_mat_all_cells_matrix,
        column_order = NULL,
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(agg_mat_all_cells_matrix)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")
## extract counts from 10x object
matrix_tenx_counts <- as.matrix(GetAssayData(pb_sex_filtered, assay = "RNA"))
#nk.raw.data <- as.matrix(GetAssayData(pb_sex_filtered, slot = "counts")[, WhichCells(pbmc, ident = "NK")])

## check it is the same as the merged object RNA slot

## check it is the same as the monocle object
matrix_tenx_counts_monocle <- as.matrix(as.data.frame((monocle.object@assays)))
## make heatmap
modules_heatmap <- Heatmap(matrix_tenx_counts,
        column_order = NULL,
        cluster_columns = TRUE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(matrix_tenx_counts)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        #bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")

plot as a function of pseudotime

Now, we will integrate the branch data we produced using slingshot and the pseudotime values to plot this heatmap.

Monocle3 has a handy function that allows us to aggregate expression of groups of cells called aggregate_gene_expression.

The code for this is located here: https://github.com/cole-trapnell-lab/monocle3/blob/1a02274209c765fe7a60f533a31b1da3dacf6785/R/cluster_genes.R

Define the groups of cells

## Split cells into groups of sexes
female_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "female"), ]
male_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "male"), ]
pre_det_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det"), ]

## inspect range of pt values to determine bin width
hist(female_cells$PT_LineageFemale)
hist(male_cells$PT_LineageMale)
hist(pre_det_cells$PT_LineageFemale)
hist(pre_det_cells$PT_LineageMale)

Use a bin width of 2

there will be two objects for the cell_group_df: male branch and female branch. Both will include the pre-det branch

## Define male and female branch cells
# male
male_branch_meta_data <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "male"), ]

male_branch_meta_data <- data.frame(cell_id = rownames(male_branch_meta_data), pt = male_branch_meta_data$PT_LineageMale)

male_cell_group_df <- male_branch_meta_data

#female
female_branch_meta_data <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "female"), ]

female_branch_meta_data <- data.frame(cell_id = rownames(female_branch_meta_data), pt = female_branch_meta_data$PT_LineageFemale)

female_cell_group_df <- female_branch_meta_data

## what's the range of values for each pt?

range(female_cell_group_df$pt)
range(male_cell_group_df$pt)
## make bin widths
# make a new col for annotation
female_cell_group_df$pt_bin <- NA
for(i in seq(2,68,2)){
  female_cell_group_df$pt_bin[which(female_cell_group_df$pt < i & female_cell_group_df$pt >= (i-2))] <- i
}

male_cell_group_df$pt_bin <- NA
for(i in seq(2,68,2)){
  male_cell_group_df$pt_bin[which(male_cell_group_df$pt < i & male_cell_group_df$pt >= (i-2))] <- i
}
# then remove old pt values
male_cell_group_df <- male_cell_group_df[ ,-2]
female_cell_group_df <- female_cell_group_df[ ,-2]
## The original object contains all cells, we just want wild-type so let's subset out gene_module_df and cell_group_df accordingly

## male
## subset out only male and pre determination cells
male_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "male" | tenx.mutant.integrated.sex@meta.data$sex == "pre-det"), ]
## take forward only wild-type
male_cells <- male_cells[which(male_cells$identity_combined == "WT" | male_cells$identity_combined == "WT_10X"), ]
#male_cells <- male_cells[which(male_cells$identity_combined == "WT_10X"), ]
## get cell names
male_cells <- rownames(male_cells)
## subset our cell group df to keep only these cells
male_cell_group_df <- male_cell_group_df[which(male_cell_group_df$cell_id %in% male_cells),]
## subset Seurat object to contain cells of interest  
male.seurat.object <- SubsetData(tenx.mutant.integrated.sex, cells = male_cells)
## make new counts and pheno:
data <- as(as.matrix(GetAssayData(male.seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(male.seurat.object@meta.data)
## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))
## Construct monocle cds
male.monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)
## preprocess
male.monocle.object = preprocess_cds(male.monocle.object, num_dim = 50, norm_method = "none")  
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
male_cell_group_df <- data.frame(cell=as.character(factor(male_cell_group_df$cell_id)), cell_group=factor(male_cell_group_df$pt_bin))  
## aggregate expression
male_agg_mat <- aggregate_gene_expression(male.monocle.object, gene_module_df_sex, male_cell_group_df, exclude.na = FALSE)

## female
## subset out only male and pre determination cells
female_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "female" | tenx.mutant.integrated.sex@meta.data$sex == "pre-det"), ]
## take forward only wild-type
female_cells <- female_cells[which(female_cells$identity_combined == "WT" | female_cells$identity_combined == "WT_10X"), ]
#female_cells <- female_cells[which(female_cells$identity_combined == "WT_10X"), ]
## get cell names
female_cells <- rownames(female_cells)
## subset our cell group df to keep only these cells
female_cell_group_df <- female_cell_group_df[which(female_cell_group_df$cell_id %in% female_cells),]
## subset Seurat object to contain cells of interest  
female.seurat.object <- SubsetData(tenx.mutant.integrated.sex, cells = female_cells)
## make new counts and pheno:
data <- as(as.matrix(GetAssayData(female.seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(female.seurat.object@meta.data)
## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))
## Construct monocle cds
female.monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)
## preprocess
female.monocle.object = preprocess_cds(female.monocle.object, num_dim = 50, norm_method = "none")  
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
female_cell_group_df <- data.frame(cell=as.character(factor(female_cell_group_df$cell_id)), cell_group=factor(female_cell_group_df$pt_bin))  
## aggregate expression
female_agg_mat <- aggregate_gene_expression(female.monocle.object, gene_module_df_sex, female_cell_group_df, exclude.na = FALSE)
## use these clusters to reorder the modules
male_agg_mat <- male_agg_mat[match(levels(gene_module_df_sex$module), row.names(male_agg_mat)), ]
female_agg_mat <- female_agg_mat[match(levels(gene_module_df_sex$module), row.names(female_agg_mat)), ]

pheatmap::pheatmap(male_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(male_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(male_agg_mat, 
                   scale="none",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(female_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(female_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(female_agg_mat, 
                   scale="none",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

ComplexHeatmap version

## pheatmap calculates Z scores for plotting values
scale_matrix_by_cols <- function (x) 
{
    m = apply(x, 1, mean, na.rm = T)
    s = apply(x, 1, sd, na.rm = T)
    return((x - m)/s)
}

## calculate z score by col
female_agg_mat_scaled <- t(as.matrix(scale_matrix_by_cols(t(female_agg_mat))))
male_agg_mat_scaled <- t(as.matrix(scale_matrix_by_cols(t(male_agg_mat))))
## reorder cols
female_agg_mat_scaled <- female_agg_mat_scaled[match(levels(gene_module_df_sex$module), row.names(female_agg_mat_scaled)), ]
male_agg_mat_scaled <- male_agg_mat_scaled[match(levels(gene_module_df_sex$module), row.names(male_agg_mat_scaled)), ]

## reorder based on clusters
genes_per_module <- genes_per_module[match(levels(gene_module_df_sex$module), row.names(genes_per_module)), ]

## change names for row names to include "module " at the begining of them
row.names(female_agg_mat_scaled) <- stringr::str_c("Module ", row.names(female_agg_mat_scaled))
row.names(male_agg_mat_scaled) <- stringr::str_c("Module ", row.names(male_agg_mat_scaled))

## add number of cells to the rownames for the module
for(i in seq_along(genes_per_module$Freq)){
  row.names(female_agg_mat_scaled)[i] <- stringr::str_c(row.names(female_agg_mat_scaled)[i]," (n = " ,genes_per_module$Freq[i], ")")
}
for(i in seq_along(genes_per_module$Freq)){
  row.names(male_agg_mat_scaled)[i] <- stringr::str_c(row.names(male_agg_mat_scaled)[i]," (n = " ,genes_per_module$Freq[i], ")")
}

## add annotation:
#heatmap_annotation <- HeatmapAnnotation(df = cluster_anno,
#                                         col = list(
# Identity = c(Male="#016c00", Female="#a52b1e", Asexual= "#0052c5", Committed = "#f2eb23")),
#                                         annotation_legend_param = list(Median_Pseudotime_of_Cluster = list(direction = "horizontal"), Identity = list(nrow = 1)))

library(ComplexHeatmap)
library(RColorBrewer)
modules_heatmap_female <- Heatmap(female_agg_mat_scaled,
        column_order = NULL,
        #row_order = row.names(female_agg_mat_scaled)[module_dendro$order],
        #clustering_method_rows = "ward.D2",
        #bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

modules_heatmap_male <- Heatmap(male_agg_mat_scaled,
        column_order = NULL,
        #row_order = module_dendro$order,
        #clustering_method_rows = "ward.D2",
        #bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

draw(modules_heatmap_female, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")
draw(modules_heatmap_male, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")

## https://www.biostars.org/p/380544/ 

4 bin width

## Define male and female branch cells
# male
male_branch_meta_data <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "male"), ]

male_branch_meta_data <- data.frame(cell_id = rownames(male_branch_meta_data), pt = male_branch_meta_data$PT_LineageMale)

male_cell_group_df <- male_branch_meta_data

#female
female_branch_meta_data <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "female"), ]

female_branch_meta_data <- data.frame(cell_id = rownames(female_branch_meta_data), pt = female_branch_meta_data$PT_LineageFemale)

female_cell_group_df <- female_branch_meta_data

## what's the range of values for each pt?

range(female_cell_group_df$pt)
range(male_cell_group_df$pt)
## make bin widths
# make a new col for annotation
female_cell_group_df$pt_bin <- NA
for(i in seq(4,68,4)){
  female_cell_group_df$pt_bin[which(female_cell_group_df$pt < i & female_cell_group_df$pt >= (i-4))] <- i
}

male_cell_group_df$pt_bin <- NA
for(i in seq(4,68,4)){
  male_cell_group_df$pt_bin[which(male_cell_group_df$pt < i & male_cell_group_df$pt >= (i-4))] <- i
}
# then remove old pt values
male_cell_group_df <- male_cell_group_df[ ,-2]
female_cell_group_df <- female_cell_group_df[ ,-2]
## The original object contains all cells, we just want wild-type so let's subset out gene_module_df and cell_group_df accordingly

## male
## subset our cell group df to keep only these cells
male_cell_group_df <- male_cell_group_df[which(male_cell_group_df$cell_id %in% male_cells),]
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
male_cell_group_df <- data.frame(cell=as.character(factor(male_cell_group_df$cell_id)), cell_group=factor(male_cell_group_df$pt_bin))  
## aggregate expression
male_agg_mat <- aggregate_gene_expression(male.monocle.object, gene_module_df_sex, male_cell_group_df, exclude.na = FALSE)

## female
## subset out only male and pre determination cells
## subset our cell group df to keep only these cells
female_cell_group_df <- female_cell_group_df[which(female_cell_group_df$cell_id %in% female_cells),]
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
female_cell_group_df <- data.frame(cell=as.character(factor(female_cell_group_df$cell_id)), cell_group=factor(female_cell_group_df$pt_bin))  
## aggregate expression
female_agg_mat <- aggregate_gene_expression(female.monocle.object, gene_module_df_sex, female_cell_group_df, exclude.na = FALSE)
## use these clusters to reorder the modules
male_agg_mat <- male_agg_mat[match(levels(gene_module_df_sex$module), row.names(male_agg_mat)), ]
female_agg_mat <- female_agg_mat[match(levels(gene_module_df_sex$module), row.names(female_agg_mat)), ]

pheatmap::pheatmap(male_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(female_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

expression of modules in mutant cells (side panels)

male

## make monocle object with mutants
## extract data
mutant_cells_male <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$genotype_combined == "Mutant" & tenx.mutant.integrated.sex@meta.data$sex == "male"),])

## make a new Seurat of this
seurat.object <-SubsetData(tenx.mutant.integrated.sex, cells = mutant_cells_male)

## make new counts and pheno:
## the reason we use the integrated and then subsetted is because these cells have been normalised whereas the cells in pb_sex_filtered have not been normalised (well they have but with doublets in them)
data <- as(as.matrix(GetAssayData(seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(seurat.object@meta.data)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))

## Construct monocle cds
monocle.object.mutants.male <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)

## preprocess
monocle.object.mutants.male = preprocess_cds(monocle.object.mutants.male, num_dim = 50, norm_method = "none")
### if using integrated data:
# norm_method = "none", alignment_group = "~ experiment"

## make a cell group dataframe for aggregating expression values:

mutant_cell_group_df <- data.frame(cell = row.names(monocle.object.mutants.male@colData), cell_group = monocle.object.mutants.male@colData$identity_updated)

## aggregate expression
mutant_male_agg_mat <- aggregate_gene_expression(monocle.object.mutants.male, gene_module_df_sex, mutant_cell_group_df)

plot

mutant_male_agg_mat <- mutant_male_agg_mat[match(levels(gene_module_df_sex$module), row.names(mutant_male_agg_mat)), ]

pheatmap::pheatmap(mutant_male_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = TRUE) + theme(legend.position = "bottom")
mutant_male_agg_mat <- mutant_male_agg_mat[match(levels(gene_module_df_sex$module), row.names(mutant_male_agg_mat)), ]

pheatmap::pheatmap(mutant_male_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = TRUE) + theme(legend.position = "bottom")

female

## make monocle object with mutants
## extract data
mutant_cells_female <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$genotype_combined == "Mutant" & tenx.mutant.integrated.sex@meta.data$sex == "female"),])

## make a new Seurat of this
seurat.object <-SubsetData(tenx.mutant.integrated.sex, cells = mutant_cells_female)

## make new counts and pheno:
## the reason we use the integrated and then subsetted is because these cells have been normalised whereas the cells in pb_sex_filtered have not been normalised (well they have but with doublets in them)
data <- as(as.matrix(GetAssayData(seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(seurat.object@meta.data)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))

## Construct monocle cds
monocle.object.mutants.female <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)

## preprocess
monocle.object.mutants.female = preprocess_cds(monocle.object.mutants.female, num_dim = 50, norm_method = "none")
### if using integrated data:
# norm_method = "none", alignment_group = "~ experiment"

## make a cell group dataframe for aggregating expression values:
mutant_cell_group_df <- data.frame(cell = row.names(monocle.object.mutants.female@colData), cell_group = monocle.object.mutants.female@colData$identity_updated)

## aggregate expression
mutant_female_agg_mat <- aggregate_gene_expression(monocle.object.mutants.female, gene_module_df_sex, mutant_cell_group_df)

plot

mutant_female_agg_mat <- mutant_female_agg_mat[match(levels(gene_module_df_sex$module), row.names(mutant_female_agg_mat)), ]

pheatmap::pheatmap(mutant_female_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE) + theme(legend.position = "bottom")
mutant_female_agg_mat <- mutant_female_agg_mat[match(levels(gene_module_df_sex$module), row.names(mutant_female_agg_mat)), ]

pheatmap::pheatmap(mutant_female_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = TRUE) + theme(legend.position = "bottom")

for particular genes (lower panel)

## landmark genes (genes of interest)
# AP2G - PBANKA-1437500
# AP2 - PBANKA-0909600 - from poran paper
# AP2G-2 - PBANKA-1034300 
list_of_mutant_genes <- c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")

list_of_genes_of_interest <- c("PBANKA-1437500", "PBANKA-0909600","PBANKA-1034300", "PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")
##make df for genes of interest
genes_of_interest <- data.frame(gene = list_of_genes_of_interest, group = c(1:length(list_of_genes_of_interest)))

## aggregate expression
## make plotting df
agg_mat_genes_of_interest <- aggregate_gene_expression(monocle.object, genes_of_interest, cell_group_df)

row.names(agg_mat_genes_of_interest) <- genes_of_interest$gene

#row.names(agg_mat_genes_of_interest) <- factor(row.names(agg_mat_genes_of_interest), levels = row.names(agg_mat_genes_of_interest)[module_dendro$order])
agg_mat_genes_of_interest <- agg_mat_genes_of_interest[,match(rownames(cluster_anno), colnames(agg_mat_genes_of_interest))]

pheatmap::pheatmap(agg_mat_genes_of_interest, 
                   scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = FALSE,
                   clustering_method="ward.D2", 
                   annotation_col = cluster_anno, 
                   annotation_colors = annotation_colours)

complex heat map

## aggregate gene expression
agg_mat_genes_of_interest <- aggregate_gene_expression(monocle.object, genes_of_interest, df_all_cells)

agg_mat_genes_of_interest <- as.matrix(agg_mat_genes_of_interest)

## make heatmap
modules_heatmap <- Heatmap(agg_mat_genes_of_interest,
        column_order = NULL,
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(agg_mat_all_cells_matrix)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")
## order cols in the matrix
agg_mat_genes_of_interest <- agg_mat_genes_of_interest[ ,match(rownames(df_anno), colnames(agg_mat_genes_of_interest))]

## make heatmap
modules_heatmap <- Heatmap(agg_mat_genes_of_interest,
        column_order = NULL,
        cluster_columns = TRUE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(agg_mat_all_cells_matrix)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")

Using Seurat to visualise cells

# find markers for every cluster compared to all remaining cells, report only the positive ones
tenx.mutant.integrated.sex.markers <- FindAllMarkers(tenx.mutant.integrated.sex, only.pos = TRUE, min.pct = 0.25, logfc.threshold = 0.25)
tenx.mutant.integrated.sex.markers %>% group_by(cluster) %>% top_n(n = 2, wt = avg_logFC)
top10 <- tenx.mutant.integrated.sex.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_logFC)
DoHeatmap(tenx.mutant.integrated.sex, features = top10$gene) + NoLegend()

But we also have the old pt values that we can use in the seurat object ie FeaturePlot(tenx.mutant.integrated.sex, reduction = “pca”, pt.size = 0.01, features = “old_pt_values”)

So let’s plot a heatmap where we plot: (x) all cells vs. (y) genes arranged by module that they belong to.

add an old pt annotation to the top

prepare data:

## extracts only 10x cells 
wt_cells <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"),])

## make a new Seurat of this
seurat.object <-SubsetData(tenx.mutant.integrated.sex, cells = wt_cells)
DoHeatmap(seurat.object, features = top10$gene) + NoLegend()
## aggregate gene expression
agg_mat_genes_of_interest <- aggregate_gene_expression(monocle.object, genes_of_interest, df_all_cells)

agg_mat_genes_of_interest <- as.matrix(agg_mat_genes_of_interest)

## make heatmap
modules_heatmap <- Heatmap(agg_mat_genes_of_interest,
        column_order = NULL,
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(agg_mat_all_cells_matrix)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")

Expression of CCP2 and MG1 by each genotype and each sex

# ccp2 - "PBANKA-1319500" - female 820
# MG1 - "PBANKA-0416100" - male 820

## make a custom dataframe:
marker_820_df <- as.data.frame(t(as.data.frame(tenx.mutant.integrated.sex@assays$RNA@data[c("PBANKA-1319500", "PBANKA-0416100"), ], stringsAsFactors=F)))
marker_820_df$cell_id <- row.names(marker_820_df)
sex_id <- data.frame(sex_at = tenx.mutant.integrated.sex@meta.data$at_sex, genotype = tenx.mutant.integrated.sex@meta.data$identity_updated ,cell_id = row.names(tenx.mutant.integrated.sex@meta.data))
marker_820_df <- merge(marker_820_df, sex_id, by = "cell_id")

ggplot(marker_820_df, aes(fill=sex_at, y=`PBANKA-1319500`, x=genotype)) + 
    geom_violin() +
  geom_jitter(shape=16, position=position_jitter(0.2)) +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 90))
#tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "female"), ]


VlnPlot(tenx.mutant.integrated.sex, group.by = "identity_updated", split.by = "at_sex", features = c("PBANKA-1319500"), split.plot = TRUE)

VlnPlot(tenx.mutant.integrated.sex, group.by = "identity_updated", split.by = "at_sex", features = c("PBANKA-0416100"), split.plot = TRUE)

Differential expression

Re-cluster the data so we have very course grain clusters

## find new clusters
tenx.mutant.integrated.sex <- FindClusters(tenx.mutant.integrated.sex, resolution = 1, random.seed = 42, algorithm = 2)

## plot the graph
DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.1") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))
VlnPlot(tenx.mutant.integrated.sex, features = c("PT_Female_UMAP", "PT_Male_UMAP"))

Show representation of genotypes per cluster

prep for dotplot

## make a dataframe that is the meta data
df_meta_data <- as.data.frame(tenx.mutant.integrated.sex@meta.data)

## define order for plotting 
my_levels_sex <- c("2", "3", "9", "6", "11", "5", "0", "10", "13", "14", "12", "8", "15", "1", "4", "7")

## redefine order of clusters:
df_meta_data$seurat_clusters <- factor(x = df_meta_data$seurat_clusters, levels = my_levels_sex)

## make a new df of CLUSTER and IDENTITY
dot_plot_df <- as.data.frame.matrix(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined))
dot_plot_df$cluster <- rownames(dot_plot_df)

## calculate percentage of cells for each genotype
dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined), margin = 2)) * 100)

## make a column for cluster names
dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)

## melt dataframe for plotting
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
colnames(dot_plot_df_pc_melted)[2] <- "identity"

## melt the raw number too
dot_plot_df_melted <- melt(dot_plot_df, variable.name = "cluster")
colnames(dot_plot_df_melted)[2] <- "identity"
colnames(dot_plot_df_melted)[3] <- "raw_number"

## merge together
identical(dot_plot_df_melted$cluster, dot_plot_df_pc_melted$cluster)
dot_plot_merged <- cbind(dot_plot_df_melted, dot_plot_df_pc_melted)
dot_plot_merged <- dot_plot_merged[,c(1,2,3,6)]

## redefine order of clusters
dot_plot_merged$cluster <- factor(x = dot_plot_merged$cluster, levels = my_levels_sex)

## where values are zero, add NA
## find wells where it's zero
zero_values <- dot_plot_merged$value == 0
dot_plot_merged$value[zero_values] <- NA

## also do for raw number
zero_values <- dot_plot_merged$raw_number == 0
dot_plot_merged$raw_number[zero_values] <- NA

## reorder x axis:
my_levels_genotype <- c("GCSKO-oom", "GCSKO-29", "GCSKO-2", "GCSKO-19", "GCSKO-3", "GCSKO-21", "GCSKO-13", "GCSKO-28", "GCSKO-10_820", "GCSKO-17", "GCSKO-20", "WT", "WT_10X")

dot_plot_merged$identity <- factor(x = dot_plot_merged$identity, levels = my_levels_genotype)

plot

## plot
dot_plot_identity <- ggplot(dot_plot_merged, aes(y = factor(cluster), x = factor(identity))) +
      ## make into a dot plot
      geom_point(aes(colour=value, size=raw_number)) + 
      scale_color_gradient(low="blue", high="red", limits=c( 0, max(dot_plot_df_pc_melted$value)), na.value="white") +
      #change the colours
      scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white") +
      theme_classic() +
      theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), text=element_text(size=16,  family="Arial")) +
      ylab("Cluster") +
      xlab("Identity") +
      theme(axis.text.x=element_text(size=12, angle=45, hjust=1, vjust=1), axis.text.y=element_text(size=12,), legend.position = "bottom", plot.margin = unit(c(1,3,1,3), "lines")) +
    ## annotate males
    geom_hline(aes(yintercept = 2.5)) +
    ## annotate females
    geom_hline(aes(yintercept = 7.5)) +
    ## annotate pheno 1
    geom_vline(aes(xintercept = 4.5)) +
    ## annotate pheno 2
    geom_vline(aes(xintercept = 5.5)) +    
    ## annotate pheno 3
    geom_vline(aes(xintercept = 7.5)) +
    ## annotate pheno 4
    geom_vline(aes(xintercept = 11.5))

## print
print(dot_plot_identity)

cut off and plot

pre_branch_cells <- c(2,3)
inmature_male_cells <- c()
inmature_female_cells <-
mature_male_cells <- 
mature_female_cells <- 

## plot the graph
DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.1") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom")
wt_cells <- row.names(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT" | tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"), ])

male_inmature_cells <- row.names(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT" | tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"), ])



early_wt_cells <- row.names(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT" && tenx.mutant.integrated.sex@meta.data$PT_LineageFemale < 46), ])

FindMarkers(tenx.mutant.integrated.sex, cells.1 = , cells.2 = )

Generate New Clusters

We must now recalculate the clusters to gain a better understanding of the heterogeneity of the subset. Since using the previous clusters, the asexual cells obscured some of the variation.

## copy old clusters
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, tenx.mutant.integrated.sex@meta.data$seurat_clusters, col.name = "pre_sex_clusters")
## generate new clusters at various resolutions
tenx.mutant.integrated.sex <- FindNeighbors(tenx.mutant.integrated.sex, dims = 1:15)
tenx.mutant.integrated.sex <- FindClusters(tenx.mutant.integrated.sex, resolution = c(2,3,4,5,6), random.seed = 42, algorithm = 2)

Visualise

Choose Cluster Resolution

View the clusters at different resolutions to chose the appropraite resolution

## plot
DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.2") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.3") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.4") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.5") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.6") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Go with 4 clusters

tenx.mutant.integrated.sex <- FindClusters(tenx.mutant.integrated.sex, resolution = 4, random.seed = 42, algorithm = 2)

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5) +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Original UMAP

You can also use the original UMAP projection

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5) +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Representation

look at cluster representation

plot

## this function writes the next bit of code for you
ploty <- c()
for(i in seq_along(levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters))){
  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
}
## plot
library(gridExtra)
grid.arrange(list_UMAPs_by_cluster[[1]] , list_UMAPs_by_cluster[[2]] , list_UMAPs_by_cluster[[3]] , list_UMAPs_by_cluster[[4]] , list_UMAPs_by_cluster[[5]] , list_UMAPs_by_cluster[[6]] , list_UMAPs_by_cluster[[7]] , list_UMAPs_by_cluster[[8]] , list_UMAPs_by_cluster[[9]] , list_UMAPs_by_cluster[[10]] , list_UMAPs_by_cluster[[11]] , list_UMAPs_by_cluster[[12]] , list_UMAPs_by_cluster[[13]] , list_UMAPs_by_cluster[[14]] , list_UMAPs_by_cluster[[15]] , list_UMAPs_by_cluster[[16]] , list_UMAPs_by_cluster[[17]] , list_UMAPs_by_cluster[[18]] , list_UMAPs_by_cluster[[19]] , list_UMAPs_by_cluster[[20]] , list_UMAPs_by_cluster[[21]] , list_UMAPs_by_cluster[[22]] , list_UMAPs_by_cluster[[23]] , list_UMAPs_by_cluster[[24]] , list_UMAPs_by_cluster[[25]] , list_UMAPs_by_cluster[[26]] , list_UMAPs_by_cluster[[27]] , list_UMAPs_by_cluster[[28]] , list_UMAPs_by_cluster[[29]] , list_UMAPs_by_cluster[[30]] , list_UMAPs_by_cluster[[31]], ncol = 5)
## for loop which takes each cluster and makes a list of cells and then plots a highlighted plot and adds it to a list

## make a df of the number of 
n_per_cluster <- as.data.frame(table(tenx.mutant.integrated.sex@meta.data$seurat_clusters))
rownames(n_per_cluster) <- n_per_cluster$Var1
n_per_cluster <- n_per_cluster[,2]

## make a blank list
list_UMAPs_by_cluster <- vector(mode = "list", length = length(levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters)))

## for loop
for(i in seq_along(levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters))){
  ## make a list of cells
  list_of_cells <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$seurat_clusters == levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters)[i]), ])
  umap_plot <- DimPlot(tenx.mutant.integrated.sex,  reduction = "umap", label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = list_of_cells) + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("cluster", levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters)[i], "\n", "(n = ", n_per_cluster[i],")")) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position = "none")
  ## add to the list
  list_UMAPs_by_cluster[[i]] <- umap_plot
}
## plot
grid.arrange(list_UMAPs_by_cluster[[1]] , list_UMAPs_by_cluster[[2]] , list_UMAPs_by_cluster[[3]] , list_UMAPs_by_cluster[[4]] , list_UMAPs_by_cluster[[5]] , list_UMAPs_by_cluster[[6]] , list_UMAPs_by_cluster[[7]] , list_UMAPs_by_cluster[[8]] , list_UMAPs_by_cluster[[9]] , list_UMAPs_by_cluster[[10]] , list_UMAPs_by_cluster[[11]] , list_UMAPs_by_cluster[[12]] , list_UMAPs_by_cluster[[13]] , list_UMAPs_by_cluster[[14]] , list_UMAPs_by_cluster[[15]] , list_UMAPs_by_cluster[[16]] , list_UMAPs_by_cluster[[17]] , list_UMAPs_by_cluster[[18]] , list_UMAPs_by_cluster[[19]] , list_UMAPs_by_cluster[[20]] , list_UMAPs_by_cluster[[21]] , list_UMAPs_by_cluster[[22]] , list_UMAPs_by_cluster[[23]] , list_UMAPs_by_cluster[[24]] , list_UMAPs_by_cluster[[25]] , list_UMAPs_by_cluster[[26]] , list_UMAPs_by_cluster[[27]] , list_UMAPs_by_cluster[[28]] , list_UMAPs_by_cluster[[29]] , list_UMAPs_by_cluster[[30]] , list_UMAPs_by_cluster[[31]], ncol = 5)

Show correspondance with old clusters (Alluvium plot, Sankey diagram)

##This is the set up for this:
## two clusters that differ
table(tenx.mutant.integrated.sex@meta.data$seurat_clusters, tenx.mutant.integrated.sex@meta.data$pre_sex_clusters)
## hemberg uses gvisSankey in https://github.com/hemberg-lab/scmap/blob/3aa2bb487a80a946469393857cea6a6effc618fb/R/Utils.R code - so maybe update with this?

## make a dataframe that is the meta data
df_meta_data <- as.data.frame(tenx.mutant.integrated.sex@meta.data)

df_alluvial <- melt(table(data.frame(full_clusters = df_meta_data$pre_sex_clusters, sex_clusters = df_meta_data$seurat_clusters)))

## load required package
#library(ggalluvial)

## plot
ggplot(df_alluvial, aes(y = value, axis1 = full_clusters, axis2 = sex_clusters)) +
  geom_alluvium(aes(fill = sex_clusters),
                width = 0, knot.pos = 0, reverse = FALSE) +
  guides(fill = FALSE) +
  geom_stratum(width = 1/8, reverse = FALSE) +
  geom_text(stat = "stratum", infer.label = TRUE, reverse = FALSE) +
  scale_x_continuous(breaks = 1:2, labels = c("original cluster", "Sex Cluster")) +
  coord_flip() +
  ggtitle("Cluster Identiity in full dataset vs. sex only") +
    theme_classic()

Show representation of genotypes per cluster

prep for dotplot

## make a dataframe that is the meta data
df_meta_data <- as.data.frame(tenx.mutant.integrated.sex@meta.data)

## define order for plotting 
my_levels_sex <- c("0", "9", "28", "2", "29", "16", "22", "23", "15", "21", "30", "4", "3", "18", "7", "8", "6", "20", "12", "26", "13", "5", "11", "25", "1", "17", "10", "24", "14", "27", "19")

## redefine order of clusters:
df_meta_data$seurat_clusters <- factor(x = df_meta_data$seurat_clusters, levels = my_levels_sex)

## make a new df of CLUSTER and IDENTITY
dot_plot_df <- as.data.frame.matrix(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined))
dot_plot_df$cluster <- rownames(dot_plot_df)

## calculate percentage of cells for each genotype
dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined), margin = 2)) * 100)

## make a column for cluster names
dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)

## melt dataframe for plotting
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
colnames(dot_plot_df_pc_melted)[2] <- "identity"

## melt the raw number too
dot_plot_df_melted <- melt(dot_plot_df, variable.name = "cluster")
colnames(dot_plot_df_melted)[2] <- "identity"
colnames(dot_plot_df_melted)[3] <- "raw_number"

## merge together
identical(dot_plot_df_melted$cluster, dot_plot_df_pc_melted$cluster)
dot_plot_merged <- cbind(dot_plot_df_melted, dot_plot_df_pc_melted)
dot_plot_merged <- dot_plot_merged[,c(1,2,3,6)]

## redefine order of clusters
dot_plot_merged$cluster <- factor(x = dot_plot_merged$cluster, levels = my_levels_sex)

## where values are zero, add NA
## find wells where it's zero
zero_values <- dot_plot_merged$value == 0
dot_plot_merged$value[zero_values] <- NA

## also do for raw number
zero_values <- dot_plot_merged$raw_number == 0
dot_plot_merged$raw_number[zero_values] <- NA

## reorder x axis:
my_levels_genotype <- c("GCSKO-oom", "GCSKO-29", "GCSKO-2", "GCSKO-19", "GCSKO-3", "GCSKO-21", "GCSKO-13", "GCSKO-28", "GCSKO-10_820", "GCSKO-17", "GCSKO-20", "WT", "WT_10X")

dot_plot_merged$identity <- factor(x = dot_plot_merged$identity, levels = my_levels_genotype)

plot

## plot
dot_plot_identity <- ggplot(dot_plot_merged, aes(y = factor(cluster), x = factor(identity))) +
      ## make into a dot plot
      geom_point(aes(colour=value, size=raw_number)) + 
      scale_color_gradient(low="blue", high="red", limits=c( 0, max(dot_plot_df_pc_melted$value)), na.value="white") +
      #change the colours
      scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white") +
      theme_classic() +
      theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), text=element_text(size=16,  family="Arial")) +
      ylab("Cluster") +
      xlab("Identity") +
      theme(axis.text.x=element_text(size=12, angle=45, hjust=1, vjust=1), axis.text.y=element_text(size=12,), legend.position = "bottom", plot.margin = unit(c(1,3,1,3), "lines")) +
    ## annotate males
    geom_hline(aes(yintercept = 5.5)) +
    ## annotate females
    geom_hline(aes(yintercept = 20.5)) +
    ## annotate pheno 1
    geom_vline(aes(xintercept = 4.5)) +
    ## annotate pheno 2
    geom_vline(aes(xintercept = 5.5)) +    
    ## annotate pheno 3
    geom_vline(aes(xintercept = 7.5)) +
    ## annotate pheno 4
    geom_vline(aes(xintercept = 11.5))

## print
print(dot_plot_identity)

4. Slingshot and SCMAP

We can then use Slingshot to plot a Pseudotime and extract mutually exclusive parts of the trajectory (Male and Female) as well as the common stalk of both trajectories.

Slingshot

packages

library(slingshot)
library(scater)

Data In

## extract the data from the objects and save to export to Arthur
integrated_sex_counts <- tenx.mutant.integrated.sex@assays$integrated@data
integrated_sex_pheno <- tenx.mutant.integrated.sex@meta.data
#saveRDS(integrated_sex_counts, file="~/data_to_export/integrated_sex_counts.RDS")
#saveRDS(integrated_sex_pheno, file="~/data_to_export/integrated_sex_pheno.RDS")
#sexcount<-readRDS("/Users/talman/Google\ Drive/ActiveSanger/sexpaper/integrated_sex_counts.RDS")
#sexpheno<-readRDS("/Users/talman/Google\ Drive/ActiveSanger/sexpaper/integrated_sex_pheno.RDS")
sexcount <- integrated_sex_counts
sexpheno <- integrated_sex_pheno

## technically this is a shortcut but it didn't work
##https://satijalab.org/seurat/v3.1/conversion_vignette.html
#convert Seurat to SCE object:
#pbmc.sce <- as.SingleCellExperiment(tenx.mutant.integrated.sex), assay = "integrated")

slingshot on PCA

Preprocess

## make a single cell experiment object, which is the input for Slingshot
sexbranch <- SingleCellExperiment(assays = list(
  counts = as.matrix(sexcount),
  logcounts = as.matrix(sexcount)
), colData = sexpheno)

## subset wild-type cells
sexbranchWT<- sexbranch[, colData(sexbranch)$genotype == "WT"|colData(sexbranch)$experiment == "tenx_5k"]

## calculate the QC metrics
sexbranchWT<-calculateQCMetrics(sexbranchWT)

## set up the colour pal
nb.cols <- 18 
mycolors <- colorRampPalette(brewer.pal(9, "Set1"))(nb.cols)

Calculate the PCS

## calculate PCA
pca <- prcomp(t(assays(sexbranchWT)$counts), scale. = FALSE)

## subset coordinates
rd1 <- pca$x[,1:2]

## plot
plot(rd1, col = rgb(0,0,0,.5), pch=16, asp = 2)

## cluster using kmeans
## you need to set a seed here to ensure the results are reproducible
set.seed(42)
cl2 <- kmeans(rd1, centers = 13)$cluster

## plot
plot(rd1, col = mycolors[cl2], asp = 3, pch = 16)

## make a nicer plot so we can interpret the clusters
df_plotting <- as.data.frame(cbind(rd1, cl2))
## change to character to make it discrete
df_plotting$cl2 <- as.character(df_plotting$cl2)
## plot
ggplot(df_plotting, aes(x = PC1, y = PC2, colour = cl2)) + 
  geom_point() + 
  scale_colour_manual(values = rainbow(13)) + 
  theme_classic()
## initialise plot to prevent error
plot.new()

## slingshot to get lineages
lin1 <- getLineages(rd1, cl2,start.clus = '8')

## make a curve through lineage 
crv1 <- getCurves(lin1)

## join points with line segments and plot
plot(rd1, col = mycolors[cl2], asp = 3, pch = 16)
lines(crv1, lwd = 3, col = 'black')

## add PCA coordinates to SCE object
reducedDims(sexbranchWT) <- SimpleList(PCA = rd1)

## add clusters to SCE object
sexbranchWT$GMM<-cl2

## Add pseudotimes to SCE object
sexbranchWT$PT_LineageFemale<-as.data.frame(slingPseudotime(crv1))$curve1
sexbranchWT$PT_LineageMale<-as.data.frame(slingPseudotime(crv1))$curve2

## add designation to SCE object
sexbranchWT$male<-is.na(sexbranchWT$PT_LineageFemale)
sexbranchWT$female<-is.na(sexbranchWT$PT_LineageMale)
vec <- vector()
for (i in 1:length(sexbranchWT$male)) {
if (sexbranchWT$male[i] == sexbranchWT$female[i]) {vec<-c(vec,"pre-det")}
  if (sexbranchWT$male[i] == TRUE) {vec<-c(vec,"male")}
  if (sexbranchWT$female[i] == TRUE) {vec<-c(vec,"female")}  
}

sexbranchWT$sex<-vec

## plot coloured by NEK3 (PBANKA_0600600)
plotPCA(sexbranchWT,shape_by="sex",colour_by="PBANKA-0600600")

slingshot on UMAP

## extracts only 10x cells 
wt_cells <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"),])

## make a new Seurat of this
seurat.object <-SubsetData(tenx.mutant.integrated.sex, cells = wt_cells)

## get UMAP coordinates
umap_coords <- seurat.object@reductions$umapoptimised_post_repca@cell.embeddings

## get clusters
#clusters <- as.list(seurat.object@meta.data$integrated_snn_res.4)
#names(clusters) <- rownames(seurat.object@meta.data)
#clusters <- as.list(clusters)
## cluster using kmeans
## you need to set a seed here to ensure the results are reproducible
set.seed(42)
clusters <- kmeans(umap_coords, centers = 13)$cluster

## plot
## make a nicer plot so we can interpret the clusters
df_plotting <- as.data.frame(cbind(umap_coords, clusters))
## change to character to make it discrete
df_plotting$clusters <- as.character(df_plotting$clusters)
## plot
ggplot(df_plotting, aes(x = umapoptimised_1, y = umapoptimised_2, colour = clusters)) + 
  geom_point() + 
  scale_colour_manual(values = rainbow(15)) + 
  theme_classic()


## initialise plot to prevent error
plot.new()

## slingshot to get lineages
lineage_uamp <- getLineages(umap_coords, clusters, start.clus = '6', end.clus = c('1', '12'))

## make a curve through lineage 
crv1 <- getCurves(lineage_uamp)

## join points with line segments and plot
plot(umap_coords, col = mycolors[clusters], asp = 3, pch = 16)
lines(crv1, lwd = 3, col = 'black')

Add data to Seurat:

## extract data to add to Seurat
## extract clusters
meta_data_to_add_from_slingshot <- data.frame(clusters_k_means_UMAP = clusters)
## Add pseudotimes
# check the length of each branch to see which curve is which using: sum(is.na(as.data.frame(slingPseudotime(crv1))$curve1))
# then inspect using the ggplot2 above to where males are - 
# tail(as.data.frame(slingPseudotime(crv1)), 100)
# tail(meta_data_to_add_from_slingshot, 100)
meta_data_to_add_from_slingshot$PT_Female_UMAP <- as.data.frame(slingPseudotime(crv1))$curve1
meta_data_to_add_from_slingshot$PT_Male_UMAP <- as.data.frame(slingPseudotime(crv1))$curve2
## add designation to SCE object
meta_data_to_add_from_slingshot$sex_UMAP <- "pre-det"
meta_data_to_add_from_slingshot$sex_UMAP[which(is.na(meta_data_to_add_from_slingshot$PT_Female_UMAP))] <- "male"
meta_data_to_add_from_slingshot$sex_UMAP[which(is.na(meta_data_to_add_from_slingshot$PT_Male_UMAP))] <- "female"

## if there are 3 curves in slingPseudotime(crv1):
#meta_data_to_add_from_slingshot$sex_UMAP[which(is.na(meta_data_to_add_from_slingshot$PT_Female_UMAP) & is.na(as.data.frame(slingPseudotime(crv1))$curve3))] <- "male"
#meta_data_to_add_from_slingshot$sex_UMAP[which(is.na(meta_data_to_add_from_slingshot$PT_Male_UMAP) & is.na(as.data.frame(slingPseudotime(crv1))$curve3))] <- "female"

## add clusters to SCE object
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, meta_data_to_add_from_slingshot)
## plot
FeaturePlot(tenx.mutant.integrated.sex, label.size = 5, pt.size = 0.5, features = c("PT_Female_UMAP", "PT_Male_UMAP")) +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

plot sex designations

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "sex_UMAP", na.value = "white") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

SCMAP

Load package

library(scmap)

Set up Index

#the reference dataset is: sexbranchWT
## set up a feature symbol column in the SCE object
rowData(sexbranchWT)$feature_symbol <- rownames(sexbranchWT)

## make an is_expr assay which only counts values with more than 0
assay(sexbranchWT, "is_expr") <- counts(sexbranchWT) > 0

## Select the top 500 most important genes
sexbranchWT <- selectFeatures(sexbranchWT, suppress_plot = FALSE, n_features = 500)

## inspect features selected
table(rowData(sexbranchWT)$scmap_features)

## create reference index
sexbranchWT <- indexCell(sexbranchWT)

## inspect results
names(metadata(sexbranchWT)$scmap_cell_index)
length(metadata(sexbranchWT)$scmap_cell_index$subcentroids)
dim(metadata(sexbranchWT)$scmap_cell_index$subcentroids[[1]])

Query dataset

#query data set is called: sexbranch
z <- sexbranch

## add feature symbol to SCE object
rowData(z)$feature_symbol <- rownames(z)

## map cells
scmapCell_results <- scmapCell(z, list(yan = metadata(sexbranchWT)$scmap_cell_index))

## copy over PCA coordinate
colData(sexbranchWT)$PC1<-as.data.frame(reducedDim(sexbranchWT))$PC1
colData(sexbranchWT)$PC2<-as.data.frame(reducedDim(sexbranchWT))$PC2

## Get nearest cell - which is located in the first row and make a list
getcells <- scmapCell_results$yan$cells[1, ]
## Extract meta data for these cells
cdsce <- colData(sexbranchWT)[getcells, ]
## Get similarity scores
topsim <- scmapCell_results$yan$similarities[1, ]

## add meta data to query dataset
# add nearest cell
z$top_pbcell <- getcells
## add PCA coordinates
z$PC1 <- cdsce$PC1
z$PC2 <- cdsce$PC2
## add assigned sex
z$sex<- cdsce$sex
## add pt
z$PT_LineageFemale<- cdsce$PT_LineageFemale
z$PT_LineageMale<- cdsce$PT_LineageMale
## add similarity score
z$topsim <- topsim

## inspect similarity scores
hist(z$topsim)

## count anything with a similarity score below 0.4 as unassigned
z$topcell_sp[z$topsim < 0.4] <- "unassigned"
z$topcell_sp <- as.factor(z$topcell_sp)
z$yt<-rep("assigned",length(z$topcell_sp))
z$yt[z$topsim < 0.4] <- "unassigned"

## extract PC scores
no <- as.data.frame(reducedDim(sexbranchWT)[,1:2])
## extract meta data
number2 <- as.data.frame(cdsce)
## extract top cell
number2$topcell_sp <- z$yt

## plot
ggplot(no, aes(PC1, PC2)) +
 geom_point(size = 1,alpha = 1/10) +
 geom_point(aes(x=PC1, y=PC2,shape=factor(topcell_sp)), data=number2, size=2, colour="black") +
 theme_classic() + scale_shape_manual(values=c(1,2))+
 scale_color_manual( values = c("0" = "#1f77b4","1" ="#ff7f0e","2" ="#2ca02c","3,0" ="#d62728","3,1" ="#9467bd","3,2"="#8c564b","3,3"="#e377c2","4"="#bcbd22","5"="#17becf","6"="#aec7e8")) + labs(x="PC1", y="PC2") 

#+
#  theme(legend.position="none", axis.title=element_text(size=8), legend.text = element_text(size = , legend.title = element_text(size #= 8), axis.text = element_text(size=:sunglasses:, axis.text.x = element_blank(), axis.text.y = element_blank())

to skip this section above and just get the data output from Arthur’s script where PCA is used as the base dimensionality reduction:

read in Arthur’s data

## read in data
at_data <- readRDS("~/data/sexbranch")

## extract values of interest
at_meta_data <- as.data.frame(at_data@colData)

## look at new cols:
head(table(at_meta_data$top_pbcell))
head(table(at_meta_data$topsim))
head(table(at_meta_data$topcell_sp))
head(table(at_meta_data$yt))
head(table(at_meta_data$sex))
#table(at_meta_data$PT_LineageFemale)
#table(at_meta_data$PT_LineageMale)

Add meta data to Seurat object

colnames_to_add_to_meta_data <- c("top_pbcell", "topsim", "topcell_sp", "yt", "sex", "PT_LineageFemale", "PT_LineageMale")

tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, metadata = at_meta_data[,which(colnames(at_meta_data) %in% colnames_to_add_to_meta_data)], col.name = c("at_top_pbcell", "at_topsim", "at_topcell_sp", "at_yt", "at_sex", "at_PT_LineageFemale", "at_PT_LineageMale"))

## to remove columns in metadata:
#tenx.mutant.integrated.sex@meta.data[136:144] <- NULL
#tenx.mutant.integrated.sex@meta.data[['NAME_OF_COL']] <- NULL

Plot sexes

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "at_sex") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))
## the slingshot pt values have NAs for e.g. male cells in the PT_LineageFemale, we can deal with this later, but for now, we will just ignore this as Dimplot will not plot NA values
#sum(is.na(tenx.mutant.integrated.sex@meta.data$at_PT_LineageMale))
#sum(is.na(tenx.mutant.integrated.sex@meta.data$at_PT_LineageFemale))

## plot
FeaturePlot(tenx.mutant.integrated.sex, label.size = 5, pt.size = 0.5, features = c("at_PT_LineageFemale", "at_PT_LineageMale")) +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Comparison of cluster way of calling males and females vs. slingshot:

table(tenx.mutant.integrated.sex@meta.data$sex)

male_clusters <- c("13", "5", "11", "25", "1", "17", "10", "24", "14", "27", "19")
female_clusters <- c("16", "22", "23", "15", "21", "30", "4", "3", "18", "7", "8", "6", "20", "12", "26")
asex_clusters <- c("0", "9", "28", "2", "29")

tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters <- NA
tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters[which(tenx.mutant.integrated.sex@meta.data$seurat_clusters %in% male_clusters)] <- "Male"
tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters[which(tenx.mutant.integrated.sex@meta.data$seurat_clusters %in% female_clusters)] <- "Female"
tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters[which(tenx.mutant.integrated.sex@meta.data$seurat_clusters %in% asex_clusters)] <- "Pre-det"

table(tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters)
table(tenx.mutant.integrated.sex@meta.data$sex, tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters)

Plot sexes

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "sex") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Plot sexes

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "sex_designation_using_clusters") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

correlation of monocle PT and

## extract pseudotime values:
pt_values <- as.data.frame(pseudotime(monocle.object, reduction_method = "UMAP"))
pt_values$cell_name <- rownames(pt_values)
meta_data_df <- as.data.frame(monocle.object@colData)
meta_data_df$cell_name <- rownames(meta_data_df)
meta_data_df <- merge(meta_data_df, pt_values, by = "cell_name")
names(meta_data_df)[142]<- "pt"

male_pt_correlation_df <- meta_data_df[which(meta_data_df$cell_name %in% male_cells), ]
female_pt_correlation_df <- meta_data_df[which(meta_data_df$cell_name %in% female_cells), ]

ggplot(male_pt_correlation_df, aes(x = PT_LineageMale, y = pt, colour = sex)) + 
  geom_point() +  
  geom_smooth(method = "lm", se = FALSE) +
  theme_classic()

ggplot(female_pt_correlation_df, aes(x = PT_LineageFemale, y = pt, colour = sex)) + 
  geom_point() + 
  geom_smooth(method = "lm", se = FALSE) +
  theme_classic()
ggplot(male_pt_correlation_df, aes(x = PT_Female_UMAP, y = pt)) + 
  geom_point() +  
  geom_smooth(method = "lm", se = FALSE) +
  theme_classic()

Save and Export

save environment

## This saves everything in the global environment for easy recall later
#save.image(file = "GCSKO_Sex_Branch_Analysis.RData")
#load(file = "GCSKO_Sex_Branch_Analysis.RData")

save modules

#gene_module_df_sex
write.csv(gene_module_df_sex, file = "../data_to_export/gene_module_df_sex.csv")
#save(pb_30k_sex_filtered, pb_sex_filtered, file = "Part_2_input.Rdata")

Save object(s)

## save integrated object to file
#saveRDS(tenx.mutant.integrated.sex, file = "../data_to_export/tenx.mutant.integrated.sex.processed.RDS") 
## restore the object
#tenx.mutant.integrated <- readRDS("../data_to_export/tenx.mutant.integrated.sex.processed.RDS")

Appendix

Functions Info

Seurat:::DoHeatmap
monocle:::plot_pseudotime_heatmap
getAnywhere(aggregate_gene_expression)
A single object matching ‘aggregate_gene_expression’ was found
It was found in the following places
  package:monocle3
  namespace:monocle3
with value

function (cds, gene_group_df = NULL, cell_group_df = NULL, norm_method = c("log", 
    "binary", "size_only"), pseudocount = 1, scale_agg_values = TRUE, 
    max_agg_value = 3, min_agg_value = -3, exclude.na = TRUE) 
{
    if (is.null(gene_group_df) && is.null(cell_group_df)) 
        stop("Error: one of either gene_group_df or cell_group_df must not be NULL")
    agg_mat <- normalized_counts(cds, norm_method = norm_method, 
        pseudocount = pseudocount)
    if (is.null(gene_group_df) == FALSE) {
        gene_group_df <- as.data.frame(gene_group_df)
        gene_group_df <- gene_group_df[gene_group_df[, 1] %in% 
            fData(cds)$gene_short_name | gene_group_df[, 1] %in% 
            row.names(fData(cds)), , drop = FALSE]
        short_name_mask <- gene_group_df[[1]] %in% fData(cds)$gene_short_name
        if (any(short_name_mask)) {
            geneids <- as.character(gene_group_df[[1]])
            geneids[short_name_mask] <- row.names(fData(cds))[match(geneids[short_name_mask], 
                fData(cds)$gene_short_name)]
            gene_group_df[[1]] <- geneids
        }
        agg_mat = as.matrix(my.aggregate.Matrix(agg_mat[gene_group_df[, 
            1], ], as.factor(gene_group_df[, 2]), fun = "sum"))
        if (scale_agg_values) {
            agg_mat <- t(scale(t(agg_mat)))
            agg_mat[agg_mat < min_agg_value] <- min_agg_value
            agg_mat[agg_mat > max_agg_value] <- max_agg_value
        }
    }
    if (is.null(cell_group_df) == FALSE) {
        cell_group_df = as.data.frame(cell_group_df)
        cell_group_df = cell_group_df[cell_group_df[, 1] %in% 
            row.names(pData(cds)), , drop = FALSE]
        agg_mat = agg_mat[, cell_group_df[, 1]]
        agg_mat = my.aggregate.Matrix(Matrix::t(agg_mat), as.factor(cell_group_df[, 
            2]), fun = "mean")
        agg_mat = Matrix::t(agg_mat)
    }
    if (exclude.na) {
        agg_mat <- agg_mat[rownames(agg_mat) != "NA", colnames(agg_mat) != 
            "NA", drop = FALSE]
    }
    return(agg_mat)
}
<bytecode: 0x7fbfccca4ff0>
<environment: namespace:monocle3>

so essentially it first takes the counts matrix and subsets it by your gene groups, then it sums the values - if you specify scale then it will calcualte the z score of the transformed dataframe

A. Diffusion Map

construct map

## construct diffusion map
## http://www.bioconductor.org/packages/devel/bioc/vignettes/slingshot/inst/doc/vignette.html
## input is a transformed expression matrix (genes as cols and cells as rows)
dm <- DiffusionMap(t(as.data.frame(tenx.mutant.integrated.sex@assays$integrated@data)))

## extract meta data for plotting
df_meta_data <- (as.data.frame(tenx.mutant.integrated.sex@meta.data))

## make combined dataframe
rd2 <- as.data.frame(cbind(DC1 = dm$DC1, DC2 = dm$DC2, identity = as.factor(as.character(tenx.mutant.integrated.sex@meta.data$post_integration_clusters))))

## plot
ggplot(rd2, aes(x = DC1, y = DC2, colour = as.character(identity))) + geom_point(size = 1) + 
  theme(axis.ticks.y = element_blank()) + 
  theme_classic()
## make a density plot for real time correlations using kasia data
## make an annotation dataframe
anno_real_time <- data.frame(monocle.object@colData$cluster_colours_figure, monocle.object@colData$pt, monocle.object@colData$Prediction.Spearman._Kasia, row.names = rownames(monocle.object@colData))
names(anno_real_time) <- c("sex", "Pseudotime", "real_time")

## change the order of the cols (cells) in data frame
col.order <- rownames(anno_real_time[with(anno_real_time, order(sex, Pseudotime)), ])
anno_real_time <- anno_real_time[col.order,]

## add an "order" col to the dataframe to assist in plotting
anno_real_time$order <- c(1:nrow(anno_real_time))

#### plot density plot x
dens1 <- ggplot(anno_real_time, aes(x = order, fill = as.factor(real_time))) + 
                geom_density(alpha = 0.2) +
                #theme_void() + 
                #theme(legend.position = "none")
                ## add annotations for sex
      geom_rect(data = cluster_anno, mapping=aes(xmin=x1, xmax=x2, ymin=y1, ymax=y2, fill=Median_Pseudotime_of_Cluster), inherit.aes = FALSE) +
    scale_fill_viridis_c(option = "plasma") +
  ## flip coordinates 
  ## geoms below will use another color scale
    new_scale_fill() +
    geom_rect(data = cluster_anno, mapping=aes(xmin=Bx1, xmax=Bx2, ymin=By1, ymax=By2, fill=Identity), inherit.aes = FALSE) +
    scale_fill_manual(values = c("Male" ="#016c00", "Female"="#a52b1e", "Asexual"= "#0052c5", "Committed" = "#f2eb23"))

dens1
LS0tCnN1YnRpdGxlOiAnR2FtZXRvY3l0ZSBEZXZlbG9wbWVudCBpbiA8aT5QbGFzbW9kaXVtIGJlcmdoZWk8L2k+Jwp0aXRsZTogfAogICFbXSguLi9HQ1NLT19sb2dvLmpwZyl7d2lkdGg9MzAwcHh9ICAKICBQc2V1ZG90aW1lIFNleHVhbCBCcmFuY2gKYXV0aG9yOiAiW0FuZHJldyBSdXNzZWxsXShodHRwczovL2FqY3J1c3NlbGwud2l4c2l0ZS5jb20vbXlzaXRlL2Fib3V0KSIKaW5zdGl0dXRlOiBXZWxsY29tZSBTYW5nZXIgSW5zdGl0dXRlCmRhdGU6ICdgciBmb3JtYXQoU3lzLkRhdGUoKSwgIiVCICVkLCAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgICN0b2NfZmxvYXQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoqKioKIyAxLiBJbnRyb2R1Y3Rpb24gYW5kIEFpbXMgey50YWJzZXR9CgpXZSBoYXZlIG1lcmdlZCB0aGUgdHdvIGRhdGFzZXRzIHRvZ2V0aGVyIGluIEdDU0tPX21lcmdlLlJtZC4gV2UgYWxzbyBzdWJzZXR0ZWQgb3V0IHRoZSBwcmUtc2V4dWFsLWJyYW5jaCBhbmQgdGhlIHNleHVhbCBjZWxscyAobWFsZSBhbmQgZmVtYWxlKSBhbmQgc3RvcmVkIHRoZW0gaW4gYSBTZXVyYXQgb2JqZWN0IGNhbGxlZCB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleC4gSGVyZSwgd2Ugd2lsbCBwZXJmb3JtIHBzZXVkb3RpbWUgYW5hbHlzaXMgb24gdGhlIGRhdGFzZXQgYW5kIGJ1aWxkIG1vZHVsZXMgb2YgZ2VuZXMgdGhhdCBzaG93IHNpbWlsYXIgZXhwcmVzc2lvbiBhY3Jvc3MgdGhpcyBwc2V1ZG90aW1lLgoKIyAyLiBSZWFkIGluIHRoZSBkYXRhICB7LnRhYnNldH0KCiMjIExvYWQvSW5zdGFsbCB0aGUgUmVxdWlyZWQgUGFja2FnZXMKCmBgYHtyIGxvYWQgcGFja2FnZXMsIGVjaG8gPSBGQUxTRX0KIyMgQ1JBTiBwYWNrYWdlcwoKIyMgUGF0Y2h3b3JrIGlzIG5lZWRlZCB0byBzdGljaCBwbG90cyB0b2dldGhlciB1c2luZyAnKycKaWYocmVxdWlyZSgicGF0Y2h3b3JrIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJwYXRjaHdvcmsgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgcGF0Y2h3b3JrIikKICAgIGluc3RhbGwucGFja2FnZXMoInBhdGNod29yayIpCiAgICBpZihyZXF1aXJlKHBhdGNod29yaykpewogICAgICAgIHByaW50KCJwYXRjaHdvcmsgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBwYXRjaHdvcmsiKQogICAgfQp9CgojIyB2aXJpZGlzIGFsbG93cyBkaWZmZXJlbnQgY29sb3VycyB0byBiZSBhZGRlZCB0byBwbG90cwppZihyZXF1aXJlKCJ2aXJpZGlzIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJ2aXJpZGlzIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIHZpcmlkaXMiKQogICAgaW5zdGFsbC5wYWNrYWdlcygidmlyaWRpcyIpCiAgICBpZihyZXF1aXJlKHZpcmlkaXMpKXsKICAgICAgICBwcmludCgidmlyaWRpcyBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIHZpcmlkaXMiKQogICAgfQp9CgojIyBTZXVyYXQgaXMgbmVlZGVkIGZvciBtb3N0IG9mIHRoaXMgc2NyaXB0CmlmKHJlcXVpcmUoIlNldXJhdCIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgICBwcmludCgiU2V1cmF0IGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIFNldXJhdCIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJTZXVyYXQiKQogICAgaWYocmVxdWlyZShTZXVyYXQpKXsKICAgICAgICBwcmludCgiU2V1cmF0IGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgU2V1cmF0IikKICAgIH0KfQoKIyMgY293cGxvdCBpcyBuZWVkZWQgZm9yIHBsb3RzIGluIHRoaXMgc2NyaXB0CmlmKHJlcXVpcmUoImNvd3Bsb3QiKSl7CiAgICBwcmludCgiY293cGxvdCBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBjb3dwbG90IikKICAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKQogICAgaWYocmVxdWlyZShjb3dwbG90KSl7CiAgICAgICAgcHJpbnQoImNvd3Bsb3QgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBjb3dwbG90IikKICAgIH0KfQoKIyMgZ3JpZEV4dHJhIGlzIG5lZWRlZCBmb3IgZ3JpZCBncmFwaGljcyB0byBwbG90IG11bHRpcGxlIHBsb3RzIGluIHRoZSBzYW1lIHZpZXcKaWYocmVxdWlyZSgiZ3JpZEV4dHJhIikpewogICAgcHJpbnQoImdyaWRFeHRyYSBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBncmlkRXh0cmEiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ3JpZEV4dHJhIikKICAgIGlmKHJlcXVpcmUoZ3JpZEV4dHJhKSl7CiAgICAgICAgcHJpbnQoImdyaWRFeHRyYSBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdyaWRFeHRyYSIpCiAgICB9Cn0KCiMjIGdyaWQgaXMgbmVlZGVkIGZvciBncmlkLmFycmFuZ2UgZnVuY3Rpb24gdG8gY2hhbmdlIHNpemUgb2YgdGl0bGUKaWYocmVxdWlyZSgiZ3JpZCIpKXsKICAgIHByaW50KCJncmlkIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGdyaWQiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ3JpZCIpCiAgICBpZihyZXF1aXJlKGdyaWQpKXsKICAgICAgICBwcmludCgiZ3JpZCBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdyaWQiKQogICAgfQp9CgojI2ZvciBkb2luZyBidWxrIGNvcnJlbGF0aW9uIGNhbGN1bGF0aW9ucwppZihyZXF1aXJlKCJIbWlzYyIpKXsKICAgIHByaW50KCJIbWlzYyBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBIbWlzYyIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJIbWlzYyIpCiAgICBpZihyZXF1aXJlKEhtaXNjKSl7CiAgICAgICAgcHJpbnQoIkhtaXNjIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgSG1pc2MiKQogICAgfQp9CgojIyByZXNoYXBlMiB0byBtZWx0IGRhdGFmcmFtZXMgZm9yIHBsb3R0aW5nOgppZihyZXF1aXJlKCJyZXNoYXBlMiIpKXsKICAgIHByaW50KCJyZXNoYXBlMiBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCByZXNoYXBlMiIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJyZXNoYXBlMiIpCiAgICBpZihyZXF1aXJlKHJlc2hhcGUyKSl7CiAgICAgICAgcHJpbnQoInJlc2hhcGUyIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgcmVzaGFwZTIiKQogICAgfQp9CgojIyB0byB3b3JrIHdpdGggZGF0YSBmcmFtZXM6CmlmKHJlcXVpcmUoImRwbHlyIikpewogICAgcHJpbnQoImRwbHlyIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGRwbHlyIikKICAgIGluc3RhbGwucGFja2FnZXMoImRwbHlyIikKICAgIGlmKHJlcXVpcmUoZHBseXIpKXsKICAgICAgICBwcmludCgiZHBseXIgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBkcGx5ciIpCiAgICB9Cn0KCiMjIG5vbi1DUkFOIHBhY2thZ2VzCgojIyBtb25vY2xlMyB0byBjYWxjdWxhdGUgcHNldWRvdGltZToKaWYocmVxdWlyZSgibW9ub2NsZTMiKSl7CiAgICBwcmludCgibW9ub2NsZTMgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgiUGxlYXNlIGluc3RhbGwgbW9ub2NsZTMgKGh0dHBzOi8vY29sZS10cmFwbmVsbC1sYWIuZ2l0aHViLmlvL21vbm9jbGUzL2RvY3MvaW5zdGFsbGF0aW9uLykiKQp9CgojIyBkZXN0aW55IGlzIHVzZWQgZm9yIGRpZmZ1c2lvbiBwbG90cyAoRGlmZnVzaW9uTWFwIGZ1bmN0aW9uKQppZihyZXF1aXJlKCJkZXN0aW55IikpewogICAgcHJpbnQoImRlc3RpbnkgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGRlc3RpbnkiKQogIGlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpCiAgQmlvY01hbmFnZXI6Omluc3RhbGwoImRlc3RpbnkiKQogIGlmKHJlcXVpcmUoZGVzdGlueSkpewogICAgICAgIHByaW50KCJkZXN0aW55IGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgZGVzdGlueSIpCiAgICB9Cn0KCiNzZXQgdGhlIHNlZWQgZm9yIGJvdGggdGhlIG1peHR1cmUgbW9kZWxzIGFuZCBhbHNvIGZvciB0aGUgc2FtcGxlIGZ1bmN0aW9uIGxhdGVyIG9uOgpzZXQuc2VlZCgtOTI0OTcpCmBgYAoKIyMgbG9hZCBkYXRhCgpgYGB7cn0KIyMgbG9hZCBzZXggb25seSBicmFuY2ggY2VsbHMgc2F2ZWQgZnJvbSBHQ1NLT19TZXhfQnJhbmNoX0FuYWx5c2lzLlJtZAojIyBSZXN0b3JlIHRoZSBvYmplY3RzCiMjIGxvYWQgc2V4IGJyYW5jaCBkYXRhc2V0CnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIHJlYWRSRFMoIi4uL2RhdGFfdG9fZXhwb3J0L3RlbngubXV0YW50LmludGVncmF0ZWQuc2V4LlJEUyIpCiMjIGxvYWQgZnVsbCBkYXRhc2V0CiN0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIHJlYWRSRFMoIi4uL2RhdGFfdG9fZXhwb3J0L3RlbngubXV0YW50LmludGVncmF0ZWQuUkRTIikKYGBgCgpgYGB7cn0KIyMgYWRkIG9sZCBwdCB2YWx1ZXMKIyMgdGhlc2UgdmFsdWVzIGFyZSBjYWxjdWxhdGVkIGluIGh0ZSBHQ1NLT19wc2V1ZG90aW1lX2FsbGNlbGxzLlJtZCBzY3JpcHQgYW5kIHNvIHdlcmUgYWRkZWQgYWZ0ZXIgdGhlIG9iamVjdCB3YXMgc3BsaXQgaW50byBzZXggb25seS4KdGVueC5hbGwgPC0gcmVhZFJEUygiLi4vZGF0YV90b19leHBvcnQvdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5SRFMiKQp0ZW54LmFsbC5tZXRhIDwtIGFzLmRhdGEuZnJhbWUodGVueC5hbGxAbWV0YS5kYXRhKQp0ZW54LmFsbC5tZXRhIDwtIHRlbnguYWxsLm1ldGFbd2hpY2gocm93bmFtZXModGVueC5hbGwubWV0YSkgJWluJSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEpKSxdCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIEFkZE1ldGFEYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCB0ZW54LmFsbC5tZXRhJG9sZF9wdF92YWx1ZXMsIGNvbC5uYW1lID0gIm9sZF9wdF92YWx1ZXMiKQojIyB0aGVuIHJlbW92ZSB0aGVzZSBvYmplY3RzIHNvIHRoZXkgZG9uJ3QgdXNlIHVwIG1lbW9yeQpybSh0ZW54LmFsbCwgdGVueC5hbGwubWV0YSkKYGBgCgpgYGB7cn0KIyMgY3JlYXRlIGEgbGlzdCBvZiBvdXIgbXV0YW50IGdlbmUgSURzCmxpc3Rfb2ZfbXV0YW50X2dlbmVzIDwtIGMoIlBCQU5LQS0wODI4MDAwIiwgIlBCQU5LQS0xMzAyNzAwIiwgIlBCQU5LQS0xNDQ3OTAwIiwgIlBCQU5LQS0wMTAyNDAwIiwgIlBCQU5LQS0wNzE2NTAwIiwgIlBCQU5LQS0xNDM1MjAwIiwgIlBCQU5LQS0xNDE4MTAwIiwgIlBCQU5LQS0xMTQ0ODAwIiwgIlBCQU5LQS0wOTAyMzAwIiwgIlBCQU5LQS0wNDEzNDAwIiwgIlBCQU5LQS0xNDU0ODAwIikKYGBgCgojIDMuIERpbWVuc2lvbmFsdHkgUmVkdWN0aW9uIHsudGFic2V0fQoKV2Ugd2lsbCBub3cgcmUtY2FsY3VsYXRlIHRoZSBVTUFQLCBQQ0EgYW5kIGRpZmZ1c2lvbiBtYXAgdG8gdmlzdWFsaXNlIHRoZSBkYXRhIHNpbmNlIHRoZSBvbGQgdmlzdWFsaXNhdGlvbiB1c2VkIHRoZSB2YXJpYXRpb24gaW4gdGhlIHdob2xlIGRhdGFzZXQgYW5kIHNvIHNvbWUgb2YgdGhlIHZhcmlhdGlvbiBpbiB0aGlzIHNldCBvZiBjZWxscyB3YXMgb2JzY3VyZWQuCgpyZWY6IGh0dHBzOi8vZ2l0aHViLmNvbS9zYXRpamFsYWIvc2V1cmF0L2lzc3Vlcy8xODgzCgojIyBBLiBSZWNhbGN1bGF0ZSBQQ0EKClRoZSBQQ0EgaXMgdXNlZCBhcyB0aGUgYmFzaXMgb2Ygb3RoZXIgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9ucyBzbyB3ZSB3aWxsIG5vdyByZWNhbGN1bGF0ZSB0aGlzIHRvIGdldCB0byBvdXIgZmluYWwgVU1BUC4KCkZpcnN0LCBydW4gUENBIGFnYWluCmBgYHtyfQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCA8LSBSdW5QQ0EodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQpgYGAKClRoZW4gaW5zcGVjdCB0aGUgUENzCmBgYHtyfQpFbGJvd1Bsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIG5kaW1zID0gMzAsIHJlZHVjdGlvbiA9ICJwY2EiKQpgYGAKCkhhdmUgYSBxdWljayBsb29rIGF0IHRoZSBvdXRwdXQKYGBge3J9CkZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAicGNhIiwgcHQuc2l6ZSA9IDAuMDEsIGZlYXR1cmVzID0gIm9sZF9wdF92YWx1ZXMiKQpgYGAKCiMjIEIuIFVNQVAKCmNhbGN1bGF0ZSBVTUFQCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30KIyMgcnVuIFVNQVAKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXggPC0gUnVuVU1BUCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjE1LCBuLm5laWdoYm9ycyA9IDIwLCBzZWVkLnVzZSA9IDEyMzQsIG1pbi5kaXN0ID0gMC41LCByZXB1bHNpb24uc3RyZW5ndGggPSAwLjA1LCByZWR1Y3Rpb24ubmFtZSA9ICJ1bWFwb3B0aW1pc2VkX3Bvc3RfcmVwY2EiKQoKIyMgcGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBzcGxpdC5ieSA9ICJnZW5vdHlwZV9jb21iaW5lZCIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKY2hlY2sgbWFya2VycyB0byBvcmllbnRhdGUKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSAxMH0KcGxvdHMgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGZlYXR1cmVzID0gYygiUEJBTktBLTEzMTk1MDAiLCAiUEJBTktBLTA0MTYxMDAiKSwgYmxlbmQgPSBUUlVFLCBjb21iaW5lID0gRkFMU0UsIGNvb3JkLmZpeGVkID0gVFJVRSwgcmVkdWN0aW9uID0gInVtYXBvcHRpbWlzZWRfcG9zdF9yZXBjYSIpCgpwbG90c1tbM11dICsgTm9MZWdlbmQoKSAgIyBHZXQganVzdCB0aGUgY28tZXhwcmVzc2lvbiBwbG90LCBidWlsdC1pbiBsZWdlbmQgaXMgbWVhbmluZ2xlc3MgZm9yIHRoaXMgcGxvdApwbG90c1tbNF1dICMgR2V0IGp1c3QgdGhlIGtleQpDb21iaW5lUGxvdHMocGxvdHNbMzo0XSwgbGVnZW5kID0gJ25vbmUnLCBuY29sID0yLCBucm93ID0gMSwgcmVsX3dpZHRocyA9IGMoMiwgMSksIHJlbF9oZWlnaHRzID0gYyg0LDEpKSAjIFN0aXRjaCB0aGUgY28tZXhwcmVzc2lvbiBhbmQga2V5IHBsb3RzIHRvZ2V0aGVyCmBgYAoKaW5zcGVjdCBtdXRhbnRzIGluIDEzIHRoYXQgYXJlIGluIGJldHdlZW4gc2V4ZXMKYGBge3J9CiMjIGdldCBtdXRhbnQgY2VsbHMKbXV0YW50X3NleF9jZWxscyA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleFt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCRnZW5vdHlwZV9jb21iaW5lZCA9PSAiTXV0YW50IiksXSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKIyMgc3Vic2V0IG9iamVjdAptdXRhbnRfb25seV9zZXVyYXQgPC0gc3Vic2V0KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBjZWxscyA9IG11dGFudF9zZXhfY2VsbHMpCgojIyBwbG90CiA8LSBEaW1QbG90KG11dGFudF9vbmx5X3NldXJhdCwgcmVkdWN0aW9uID0gInVtYXBvcHRpbWlzZWRfcG9zdF9yZXBjYSIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKYGBgCgoKCiMgNC4gQ2x1c3RlcmluZyB7LnRhYnNldH0KCiMjIyBJbnZlc3RpZ2F0ZSBzdWIgY2x1c3RlcmluZyBvZiBwcmUtYnJhbmNoIGNsdXN0ZXJzCgpVbHRpbWF0ZWx5LCB3ZSBhcmUgbG9va2luZyBmb3IgY29leHByZXNzaW9uIGFmdGVyIHRoZSBleHByZXNzaW9uIG9mIEFQMkc6CmBgYHtyfQojIyBwbG90Cm1hcmtlcl9nZW5lX3Bsb3RfQVAyRyA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgZmVhdHVyZXMgPSAiUEJBTktBLTE0Mzc1MDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBwdC5zaXplID0gMSwgb3JkZXIgPSBUUlVFKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiQVAyRyBFeHByZXNzaW9uIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsgCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkKCiMjdmlldwptYXJrZXJfZ2VuZV9wbG90X0FQMkcKYGBgCmFuZCB3ZSBoYXZlIHRoZSBmb2xsb3dpbmcgY2x1c3RlcnMgY3VycmVudGx5OgoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA0fQojIyBQbG90CnVtYXBfY2x1c3RlciA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBsYWJlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA4LCByZXBlbCA9IEZBTFNFLCBwdC5zaXplID0gMC41LCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwgCiAgICAgICAgYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSkgKyAKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93ID0gMywgYnlyb3cgPSBUUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NSkpKQoKIyMgcHJpbnQKdW1hcF9jbHVzdGVyCmBgYAoKMTMgaXMgdGhlIGNvbW1vbiBzZXggYnJhbmNoIHNvIHdlIHdpbGwgaW50ZXJyb2dhdGUgdGhhdCBicmFuY2gKCmBgYHtyfQojIyBzdWJzZXQgY2x1c3RlciAxMyBjZWxscwpjZWxsc190aGlydGVlbiA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyA9PSAxMywgXSkKCiMjIHN1YnNldCBjbHVzdGVyIDEzCnNldXJhdF90aGlydGVlbiA8LSBzdWJzZXQodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gY2VsbHNfdGhpcnRlZW4pCgojIyByZS1QQ0EKc2V1cmF0X3RoaXJ0ZWVuIDwtIFJ1blBDQShzZXVyYXRfdGhpcnRlZW4sIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQpFbGJvd1Bsb3Qoc2V1cmF0X3RoaXJ0ZWVuLCBuZGltcyA9IDMwLCByZWR1Y3Rpb24gPSAicGNhIikKCiMjIHJlY2x1c3RlcgpzZXVyYXRfdGhpcnRlZW4gPC0gRmluZE5laWdoYm9ycyhzZXVyYXRfdGhpcnRlZW4sIGRpbXMgPSAxOjE1KQpzZXVyYXRfdGhpcnRlZW4gPC0gRmluZENsdXN0ZXJzKHNldXJhdF90aGlydGVlbiwgcmVzb2x1dGlvbiA9IDEsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCgojIyBwbG90IGNsdXN0ZXIgcmVzb2x1dGlvbiA9IDEKIyMgcGxvdApEaW1QbG90KHNldXJhdF90aGlydGVlbiwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgIGRpbXMgPSBjKDIsMSksIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjEiKSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3c9MyxieXJvdz1UUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQpgYGAKCjIgYW5kIDEgYXJlIHN1cGVyaW1wb3NlZCBvbiB0aGUgYnJhbmNoLCBsZXRzIGZpbmQgbWFya2VycyBmb3IgZWFjaCBjbHVzdGVyCgpgYGB7cn0KIyMgZmluZCBtYXJrZXJzCnNldXJhdF90aGlydGVlbl9tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKHNldXJhdF90aGlydGVlbiwgb25seS5wb3MgPSBGQUxTRSwgbWluLnBjdCA9IDAuMjUsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUpCgojIyBpbnNwZWN0IHJlc3VsdAptYXJrZXJzX3N1YnNldCA8LSBzZXVyYXRfdGhpcnRlZW5fbWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG4gPSA1MCwgd3QgPSBhdmdfbG9nRkMpICU+JSBmaWx0ZXIocF92YWxfYWRqIDwgMC4wNSkKbWFya2Vyc19zdWJzZXQKCiMjIGZpbmQgbWFya2VycwptYXJrZXJzX3N1YnNldF9tdXRhbnQgPC0gbWFya2Vyc19zdWJzZXRbd2hpY2gobWFya2Vyc19zdWJzZXQkZ2VuZSAlaW4lIGxpc3Rfb2ZfbXV0YW50X2dlbmVzKSwgXQptYXJrZXJzX3N1YnNldF9tdXRhbnQKCiMjIHBsb3QKVmxuUGxvdChzZXVyYXRfdGhpcnRlZW4sIGZlYXR1cmVzID0gYyhtYXJrZXJzX3N1YnNldF9tdXRhbnQkZ2VuZSwgIlBCQU5LQS0xNDM3NTAwIiksIGFzc2F5ID0gIlJOQSIpCmBgYApTcGVjaWZpY2FsbHkgbG9vayBmb3IgbWFya2VycyBiZXR3ZWVuIDEgYW5kIDIKYGBge3J9CmNsdXN0ZXJfMV8yX21hcmtlcnMgPC0gRmluZE1hcmtlcnMoc2V1cmF0X3RoaXJ0ZWVuLCBpZGVudC4xID0gMSwgaWRlbnQuMiA9IDIsIG9ubHkucG9zID0gRkFMU0UsIG1pbi5wY3QgPSAwLjI1LCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1KQoKY2x1c3Rlcl8xXzJfbWFya2Vyc19zdWJzZXQgPC0gY2x1c3Rlcl8xXzJfbWFya2VycyAlPiUgZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUpCmNsdXN0ZXJfMV8yX21hcmtlcnNfc3Vic2V0CmBgYApKdXN0IGNoZWNrIHRoYXQgbXV0YW50cyBhcmVuJ3QgaW50ZXJmZXJpbmcgIHdpdGggdGhlIGFuYWx5c2lzIGkuZS4gdGhlIGNsdXN0ZXJzIGRvbid0IGp1c3QgYmVsb25nIHRvIGEgY2VydGFpbiBnZW5vdHlwZSBvciBtdXRhbnQgY2VsbApgYGB7cn0KdGFibGUoc2V1cmF0X3RoaXJ0ZWVuJHNldXJhdF9jbHVzdGVycywgc2V1cmF0X3RoaXJ0ZWVuJGlkZW50aXR5X2NvbWJpbmVkKQpgYGAKCkRvIHRoZSBzYW1lIGFuYWx5c2lzIG9uIGNsdXN0ZXIgMyBxdWlja2x5CmBgYHtyfQojIyBzdWJzZXQgY2x1c3RlciAxMyBjZWxscwpjZWxsc190aHJlZSA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyA9PSAzLCBdKQoKIyMgc3Vic2V0IGNsdXN0ZXIgMTMKY2VsbHNfdGhyZWUgPC0gc3Vic2V0KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBjZWxscyA9IGNlbGxzX3RocmVlKQoKIyMgcmUtUENBCmNlbGxzX3RocmVlIDwtIFJ1blBDQShjZWxsc190aHJlZSwgbnBjcyA9IDMwLCB2ZXJib3NlID0gRkFMU0UpCkVsYm93UGxvdChjZWxsc190aHJlZSwgbmRpbXMgPSAzMCwgcmVkdWN0aW9uID0gInBjYSIpCgojIyByZWNsdXN0ZXIKY2VsbHNfdGhyZWUgPC0gRmluZE5laWdoYm9ycyhjZWxsc190aHJlZSwgZGltcyA9IDE6NSkKIyMgZmlyc3QgZG8gYSBjKDAuNSwxLDIpIGZvciByZXNvbHV0aW9uIGFuZCB0aGVuIHBpY2sgYSBzZW5zaWJsZSBjbHVzdGVyIG51bWJlcgpjZWxsc190aHJlZSA8LSBGaW5kQ2x1c3RlcnMoY2VsbHNfdGhyZWUsIHJlc29sdXRpb24gPSAwLjUsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCgojIyBwbG90IGNsdXN0ZXIgcmVzb2x1dGlvbiA9IDEKIyMgcGxvdApEaW1QbG90KGNlbGxzX3RocmVlLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCAgZGltcyA9IGMoMiwxKSwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMC41IikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKYGBgCgpgYGB7cn0KIyMgZmluZCBtYXJrZXJzCmNlbGxzX3RocmVlX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoY2VsbHNfdGhyZWUsIG9ubHkucG9zID0gRkFMU0UsIG1pbi5wY3QgPSAwLjI1LCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1KQoKIyMgaW5zcGVjdCByZXN1bHQKbWFya2Vyc19zdWJzZXQgPC0gY2VsbHNfdGhyZWVfbWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG4gPSA1MCwgd3QgPSBhdmdfbG9nRkMpICU+JSBmaWx0ZXIocF92YWxfYWRqIDwgMC4wNSkKbWFya2Vyc19zdWJzZXQKCiMjIGZpbmQgbWFya2VycwptYXJrZXJzX3N1YnNldF9tdXRhbnQgPC0gbWFya2Vyc19zdWJzZXRbd2hpY2gobWFya2Vyc19zdWJzZXQkZ2VuZSAlaW4lIGxpc3Rfb2ZfbXV0YW50X2dlbmVzKSwgXQptYXJrZXJzX3N1YnNldF9tdXRhbnQKCiMjIHBsb3QKVmxuUGxvdChjZWxsc190aHJlZSwgZmVhdHVyZXMgPSBjKG1hcmtlcnNfc3Vic2V0X211dGFudCRnZW5lLCAiUEJBTktBLTE0Mzc1MDAiKSwgYXNzYXkgPSAiUk5BIikKYGBgCgpgYGB7cn0KZGZfcGxvdCA8LSBkYXRhLmZyYW1lKHQoZGF0YS5mcmFtZShjZWxsc190aHJlZUBhc3NheXMkUk5BW2MoIlBCQU5LQS0xNDQ3OTAwIiwgIlBCQU5LQS0xNDM3NTAwIiksIF0pKSkKCmdncGxvdChkZl9wbG90LCBhZXMoUEJBTktBLjE0NDc5MDAsIFBCQU5LQS4xNDM3NTAwKSkgKyBnZW9tX3BvaW50KCkKYGBgCgojIDYuIE1vbm9jbGUgb24gc2V4IGNlbGxzIHsudGFic2V0fQoKIyMgY2FsY3VsYXRlIHBzZXVkb3RpbWUgYW5kIG1vZHVsZXMKCiMjIyMgUHJlcGFyYXRpb24KYGBge3J9CiMjIGV4dHJhY3RzIG9ubHkgMTB4IGNlbGxzIGFuZCBhbHNvIHJlbW92ZSBjbHVzdGVyIDAgY2VsbHMgCnd0X2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkaWRlbnRpdHlfY29tYmluZWQgPT0gIldUXzEwWCIgJiAhdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyA9PSAiMCIpLF0pCgojIyBtYWtlIGEgbmV3IFNldXJhdCBvZiB0aGlzCnNldXJhdC5vYmplY3QgPC1zdWJzZXQodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gd3RfY2VsbHMpCgojIyBjaGVjayB0aGF0IHRoaXMgaXMgdGhlIHNhbWUgYXMgdGhlIHBiX3NleF9maWx0ZXJlZCBvYmplY3QKI2RhdGFfdGVzdCA8LSBhcyhhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKHBiX3NleF9maWx0ZXJlZCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikpLCAnc3BhcnNlTWF0cml4JykKI2lzLmVxdWFsCiNpcy5pZGVudGljYWwKCiMjIGV4dHJhY3QgY291bnRzIGFuZCBwaGVubzoKIyMgdGhlIHJlYXNvbiB3ZSB1c2UgdGhlIGludGVncmF0ZWQgYW5kIHRoZW4gc3Vic2V0dGVkIGlzIGJlY2F1c2UgdGhlc2UgY2VsbHMgaGF2ZSBiZWVuIG5vcm1hbGlzZWQgd2hlcmVhcyB0aGUgY2VsbHMgaW4gcGJfc2V4X2ZpbHRlcmVkIGhhdmUgbm90IGJlZW4gbm9ybWFsaXNlZCAod2VsbCB0aGV5IGhhdmUgYnV0IHdpdGggZG91YmxldHMgaW4gdGhlbSkKZGF0YSA8LSBhcyhhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKHNldXJhdC5vYmplY3QsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCiMjIG1ha2UgcGhlbm9kYXRhCnBkIDwtIGRhdGEuZnJhbWUoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpCiMjIGtlZXAgb25seSB0aGUgY29sdW1ucyB0aGF0IGFyZSByZWxldmFudCBpbiBtZXRhZGF0YQojcERhdGEgPC0gcGQgJT4lIHNlbGVjdChvcmlnLmlkZW50LCBuQ291bnRfUk5BLCBuRmVhdHVyZV9STkEpCiMjIG1ha2UgZ2VuZSBtZXRhZGF0YQpmRGF0YSA8LSBkYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IHJvdy5uYW1lcyhkYXRhKSwgcm93Lm5hbWVzID0gcm93Lm5hbWVzKGRhdGEpKQoKIyMgQ29uc3RydWN0IG1vbm9jbGUgY2RzCm1vbm9jbGUub2JqZWN0IDwtIG5ld19jZWxsX2RhdGFfc2V0KGV4cHJlc3Npb25fZGF0YSA9IGRhdGEsIGNlbGxfbWV0YWRhdGEgPSBwZCwgZ2VuZV9tZXRhZGF0YSA9IGZEYXRhKQoKIyMgcHJlcHJvY2Vzcwptb25vY2xlLm9iamVjdCA9IHByZXByb2Nlc3NfY2RzKG1vbm9jbGUub2JqZWN0LCBudW1fZGltID0gNTAsIG5vcm1fbWV0aG9kID0gIm5vbmUiKQojIyMgaWYgdXNpbmcgaW50ZWdyYXRlZCBkYXRhOgojIG5vcm1fbWV0aG9kID0gIm5vbmUiLCBhbGlnbm1lbnRfZ3JvdXAgPSAifiBleHBlcmltZW50IgoKIyMgcGxvdCBqYWNrIHN0cmF3IHBsb3QKI3Bsb3RfcGNfdmFyaWFuY2VfZXhwbGFpbmVkKG1vbm9jbGUub2JqZWN0KQoKI21vbm9jbGUub2JqZWN0ID0gcmVkdWNlX2RpbWVuc2lvbihtb25vY2xlLm9iamVjdCwgcmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIiwgcHJlcHJvY2Vzc19tZXRob2QgPSAiUENBIiwgdW1hcC5tZXRyaWMgPSAiZXVjbGlkZWFuIiwgdW1hcC5uX25laWdoYm9ycyA9IDUwLCB1bWFwLm1pbl9kaXN0ID0gMC41LCB2ZXJib3NlID0gRkFMU0UpCgojcGxvdF9jZWxscyhtb25vY2xlLm9iamVjdCwgY29sb3JfY2VsbHNfYnk9ImV4cGVyaW1lbnQiKQoKIyMgZ3JhcGggbGVhcm5pbmcKCiMjIGFkZCBVTUFQIGZyb20gU2V1cmF0Cm1vbm9jbGUub2JqZWN0QGludF9jb2xEYXRhQGxpc3REYXRhJHJlZHVjZWREaW1zQGxpc3REYXRhW1siVU1BUCJdXSA8LSBzZXVyYXQub2JqZWN0QHJlZHVjdGlvbnNbWyJESU1fVU1BUCJdXUBjZWxsLmVtYmVkZGluZ3MKCiMjIGNsdXN0ZXIKIyMgdGhpcyBpcyBlc3NlbnRpYWwgdG8gcnVuIHRoZSBsZWFybl9ncmFwaCBmdW5jdGlvbiBsYXRlciBvbgptb25vY2xlLm9iamVjdCA9IGNsdXN0ZXJfY2VsbHMobW9ub2NsZS5vYmplY3QpCgojIyBwbG90IGluaXRpYWwgY2x1c3RlcmluZyBieSBtb25vY2xlCiNwbG90X2NlbGxzKG1vbm9jbGUub2JqZWN0LCBjb2xvcl9jZWxsc19ieT0iY2x1c3RlciIsIGdyb3VwX2NlbGxzX2J5PSJwYXJ0aXRpb24iLCB4ID0gMiwgeSA9IDEpCgojIyBtYXAgcHNldWRvdGltZQptb25vY2xlLm9iamVjdCA9IGxlYXJuX2dyYXBoKG1vbm9jbGUub2JqZWN0LCBsZWFybl9ncmFwaF9jb250cm9sPWxpc3QobmNlbnRlcj01MDApLCB1c2VfcGFydGl0aW9uID0gRkFMU0UpCiMgbGVhcm5fZ3JhcGhfY29udHJvbD1saXN0KG5jZW50ZXI9NTAwKSAtIHBsYXkgd2l0aCB0aGlzIHBhcmFtZXRlcgoKIyMgUGxvdCBjZWxscwpwbG90X2NlbGxzKG1vbm9jbGUub2JqZWN0LCBjb2xvcl9jZWxsc19ieT0icGFydGl0aW9uIiwgZ3JvdXBfY2VsbHNfYnk9InBhcnRpdGlvbiIsIHggPSAyLCB5ID0gMSkKYGBgCgoKIyMjIyBQc2V1ZG90aW1lIENhbGN1bGF0aW9uCmBgYHtyfQojIyBPcmRlciB0aGUgY2VsbHMgYW5kIGNhbGN1bGF0ZSBwc2V1ZG90aW1lCm1vbm9jbGUub2JqZWN0ID0gb3JkZXJfY2VsbHMobW9ub2NsZS5vYmplY3QpCgojIyBQbG90CnVtYXBfcHQgPC0gcGxvdF9jZWxscyhtb25vY2xlLm9iamVjdCwgY29sb3JfY2VsbHNfYnkgPSAicHNldWRvdGltZSIsIGxhYmVsX2NlbGxfZ3JvdXBzPUZBTFNFLCBjZWxsX3NpemUgPSAxLCB4ID0gMiwgeSA9IDEsIGxhYmVsX2JyYW5jaF9wb2ludHM9RkFMU0UsIGxhYmVsX2xlYXZlcz1GQUxTRSwgbGFiZWxfZ3JvdXBzX2J5X2NsdXN0ZXI9RkFMU0UsIGxhYmVsX3Jvb3RzID0gRkFMU0UpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIGxhYnModGl0bGUgPSAiUHNldWRvdGltZSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCiMjIHZpZXcKdW1hcF9wdApgYGAKc2F2ZQpgYGB7cn0KZ2dzYXZlKCIuLi9pbWFnZXNfdG9fZXhwb3J0L0dDU0tPX3NleGJyYW5jaF91bWFwX3B0LnBuZyIsIHBsb3QgPSB1bWFwX3B0LCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCkp1c3QgY2hlY2sgaWYgdGhlICdob29rJyBvbiB0aGUgbWFsZXMgaXMgYSBsaW5lYWdlIG9yIGRlYWQvZHlpbmcvYWN0aXZhdGVkIGdhbXMsIG9yIG11dGFudHMKCmBgYHtyfQpGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgZmVhdHVyZXMgPSAiUEJBTktBLTA0MTYxMDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBwdC5zaXplID0gMSwgb3JkZXIgPSBUUlVFKSArIAogICAgICAgICAgICB0aGVtZV92b2lkKCkgKyAKICAgICAgICAgICAgbGFicyh0aXRsZSA9IHBhc3RlKCJNRzEgKE1hbGUpIikpICsgCiAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKSArIAogICAgICAgICAgICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKQpgYGAKCkl0IGFwcGVhcnMgTUcxIG1hcmtlciBleHByZXNzaW9uIGlzIGRlY3JlYXNpbmcvb2ZmIGluIHRoZXNlIGNlbGxzIC0gaW5zcGVjdCBtdXRhbnQgc3RhdHVzCgpgYGB7ciwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDR9CnBsb3QgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwgPSBGQUxTRSwgbGFiZWwuc2l6ZSA9IDgsIHJlcGVsID0gRkFMU0UsIHB0LnNpemUgPSAwLjA1LCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBncm91cC5ieSA9ICJpZGVudGl0eV91cGRhdGVkIikgKyAKICBjb29yZF9maXhlZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIAogICAgICAgIGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdyA9IDMsIGJ5cm93ID0gVFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUpKSkKCkhvdmVyTG9jYXRvcihwbG90ID0gcGxvdCwgaW5mb3JtYXRpb24gPSBGZXRjaERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHZhcnMgPSBjKCJpZGVudCIsICJpZGVudGl0eV91cGRhdGVkIiwgIm5GZWF0dXJlX1JOQSIpKSkKYGBgCgojIyMjIENoZWNrIGhvdyB3ZWxsIGl0IGNvcnJlbGF0ZXMgd2l0aCB0aGUgb3JpZ2luYWwgcHNldWRvdGltZQoKd2hlbiBwc2V1ZG90aW1lIHdhcyBjYWxjdWFsdGVkIG9uIHRoZSB3aG9sZSBvYmplY3QKCmBgYHtyfQpsaWJyYXJ5KGdncHVicikKIyMgZXh0cmFjdCBwc2V1ZG90aW1lIHZhbHVlczoKcHRfdmFsdWVzX25ldyA8LSBhcy5kYXRhLmZyYW1lKHBzZXVkb3RpbWUobW9ub2NsZS5vYmplY3QsIHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIpKQpwdF92YWx1ZXNfbmV3JGNlbGxfbmFtZSA8LSByb3duYW1lcyhwdF92YWx1ZXNfbmV3KQptZXRhX2RhdGFfZGYgPC0gYXMuZGF0YS5mcmFtZShtb25vY2xlLm9iamVjdEBjb2xEYXRhKQptZXRhX2RhdGFfZGYkY2VsbF9uYW1lIDwtIHJvd25hbWVzKG1ldGFfZGF0YV9kZikKbWV0YV9kYXRhX2RmIDwtIG1lcmdlKG1ldGFfZGF0YV9kZiwgcHRfdmFsdWVzX25ldywgYnkgPSAiY2VsbF9uYW1lIikKbmFtZXMobWV0YV9kYXRhX2RmKVtuY29sKG1ldGFfZGF0YV9kZildPC0gInB0IgoKZ2dwbG90KG1ldGFfZGF0YV9kZiwgYWVzKHggPSBvbGRfcHRfdmFsdWVzLCB5ID0gcHQsIGNvbG91ciA9IGNsdXN0ZXJfY29sb3Vyc19maWd1cmUpKSArIAogIGdlb21fcG9pbnQoKSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgdGhlbWVfY2xhc3NpYygpICsgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iKQpgYGAKClRoaXMgc2hvd3MgdmVyeSBnb29kIGNvcnJlbGF0aW9uLCBhbmQgdGhlIGZlbWFsZXMgaGF2ZSBhIHNsaWdodGx5IGRpZmZlcmVudCBjb3JyZWxhdGlvbiBidXQgd2UgY2FuIHNlZSB0aGF0IHRoZSBicmFuY2hlcyBmaXQgd2VsbCBvbiB0aGUgVU1BUC4KCiMjIyMgSXNvbGF0ZSBCcmFuY2hlcwoKYGBge3J9CiMjIGFjY2VzcyB0aGUgY2xvc2VzdCBwcmluY2lwYWwgZ3JhcGggbm9kZSB2ZXJ0ZXggZm9yIGVhY2ggY2VsbCBhbmQgYXNzaWduIGl0IGFzIGEgY29sdW1uIGluIHlvdXIgY29sRGF0YSB0YWJsZSB1c2luZwojY29sRGF0YShtb25vY2xlLm9iamVjdCkkY2xvc2VzdF92ZXJ0ZXggPC0gbW9ub2NsZS5vYmplY3RAcHJpbmNpcGFsX2dyYXBoX2F1eFtbIlVNQVAiXV0kcHJfZ3JhcGhfY2VsbF9wcm9qX2Nsb3Nlc3RfdmVydGV4WywxXQoKIyMgcGxvdAojcGxvdF9jZWxscyhtb25vY2xlLm9iamVjdCwgY29sb3JfY2VsbHNfYnkgPSAiY2xvc2VzdF92ZXJ0ZXgiLCBsYWJlbF9jZWxsX2dyb3VwcyA9IEZBTFNFKQpgYGAKCiMjIyMgTW9kdWxlIENvbnN0cnVjdGlvbgpgYGB7cn0KIyMgZmluZCBnZW5lcyB0aGF0IGNoYW5nZSBhcyBhIGZ1bmN0aW9uIG9mIHB0Ogptb25vY2xlLm9iamVjdF9wcl90ZXN0X3JlcyA8LSBncmFwaF90ZXN0KG1vbm9jbGUub2JqZWN0LCBuZWlnaGJvcl9ncmFwaD0icHJpbmNpcGFsX2dyYXBoIiwgY29yZXM9OCkKCiMjIGZpbmQgc2lnbmlmaWNhbnQgZ2VuZXMKIyMgSSB1c2VkIDAuMDUgcHJldmlvdXNseSBpbiBhbGwgY2VsbHMgCiMjIDI4ODQgdy4gcCA9IDAuMDEsIDMyNjAgdy4gcCA9IDAuMDUKcHJfZGVnX2lkcyA8LSByb3cubmFtZXMoc3Vic2V0KG1vbm9jbGUub2JqZWN0X3ByX3Rlc3RfcmVzLCBxX3ZhbHVlIDwgMC4wNSkpCgojIyBjb2xsZWN0IGludG8gbW9kdWxlcwpnZW5lX21vZHVsZV9kZl9zZXggPC0gZmluZF9nZW5lX21vZHVsZXMobW9ub2NsZS5vYmplY3RbcHJfZGVnX2lkcyxdLCByZXNvbHV0aW9uPWMoMTBec2VxKC02LDIpKSwgcmFuZG9tX3NlZWQgPSAxMjM0KQoKIyMgaG93IG1hbnkgZ2VuZXMgaW4gbW9kdWxlcz8KZGltKGdlbmVfbW9kdWxlX2RmX3NleCkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFfQpwYXN0ZSgidGhlcmUgYXJlIiwgbGVuZ3RoKGxldmVscyhnZW5lX21vZHVsZV9kZl9zZXgkbW9kdWxlKSksICJtb2R1bGVzIikKYGBgCgojIyBQbG90IE1vZHVsZXMKCiMjIyMgR2VuZXJhbCBNb2R1bGUgQ29tcG9zaXRpb24KCk1ha2UgYSBkYXRhZnJhbWUgdG8gcGxvdCBieSBhZ2dyZWdhdGluZyBjbHVzdGVycyB2cy4gbW9kdWxlcwpgYGB7cn0KIyMgbWFrZSBjZWxsIGdyb3VwIGRmCmNlbGxfZ3JvdXBfZGYgPC0gdGliYmxlOjp0aWJibGUoY2VsbD1yb3cubmFtZXMoY29sRGF0YShtb25vY2xlLm9iamVjdCkpLCBjZWxsX2dyb3VwPWNvbERhdGEobW9ub2NsZS5vYmplY3QpJHNldXJhdF9jbHVzdGVycykKCiMjIG1ha2UgcGxvdHRpbmcgZGYKYWdnX21hdCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1vbm9jbGUub2JqZWN0LCBnZW5lX21vZHVsZV9kZl9zZXgsIGNlbGxfZ3JvdXBfZGYpCmBgYAoKRmluZCBvdXQgaG93IG1hbnkgZ2VuZXMgdGhlcmUgYXJlIHBlciB0b3RhbCBzbyB3ZSBjYW4gYWRkIHRoaXMgdG8gdGhlIHBsb3QKYGBge3J9CiMjIGhvdyBtYW55IGdlbmVzIHBlciBtb2R1bGU/CmdlbmVzX3Blcl9tb2R1bGUgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShnZW5lX21vZHVsZV9kZl9zZXgkbW9kdWxlKSkKZ2VuZXNfcGVyX21vZHVsZQpgYGAKCkZpbmQgb3V0IHdoaWNoIG1vZHVsZXMgb3VyIG11dGFudCBnZW5lcyByZXNpZGUgaW4KYGBge3J9CiMjIGNyZWF0ZSBhIGxpc3Qgb2Ygb3VyIG11dGFudCBnZW5lIElEcwpsaXN0X29mX211dGFudF9nZW5lcyA8LSBjKCJQQkFOS0EtMDgyODAwMCIsICJQQkFOS0EtMTMwMjcwMCIsICJQQkFOS0EtMTQ0NzkwMCIsICJQQkFOS0EtMDEwMjQwMCIsICJQQkFOS0EtMDcxNjUwMCIsICJQQkFOS0EtMTQzNTIwMCIsICJQQkFOS0EtMTQxODEwMCIsICJQQkFOS0EtMTE0NDgwMCIsICJQQkFOS0EtMDkwMjMwMCIsICJQQkFOS0EtMDQxMzQwMCIsICJQQkFOS0EtMTQ1NDgwMCIpCgojIyBtYWtlIGEgZGF0YWZyYW1lIHRvIGNvbnZlcnQgdGhlIGdlbmUgSURzIGludG8gYWN0dWFsIElEcwpkZl9tdXRhbnRfaWRzIDwtIGFzLmRhdGEuZnJhbWUodW5pcXVlKGNiaW5kKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X2dlbmVfdXBkYXRlZCwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCkpKVstYygxLCAzKSxdCiMgcmVtb3ZlIHRoZSAiODIwIiBiaXQgb24gMTAKZGZfbXV0YW50X2lkcyRWMSA8LSBnc3ViKCJfODIwIiwgIiIsIGRmX211dGFudF9pZHMkVjEpCiMgY2hhbmdlIHRoZSB1bmRlcnNjb3JlIChfKSB0byBhIGRhc2ggKC0pIGluIGdlbmUgSURzCmRmX211dGFudF9pZHMkVjEgPC0gZ3N1YigiXyIsICItIiwgZGZfbXV0YW50X2lkcyRWMSkKbmFtZXMoZGZfbXV0YW50X2lkcykgPC0gYygiZ2VuZV9JRCIsICJtdXRhbnRfaWRlbnRpdHkiKQoKIyMgc3Vic2V0IG1vZHVsZXMgZGYgdG8gaW5jbHVkZSBvbmx5IG11dGFudCBnZW5lIElEcwpkZl9tdXRhbnRfZ2VuZV9tb2R1bGVzIDwtIGFzLmRhdGEuZnJhbWUoZ2VuZV9tb2R1bGVfZGZfc2V4W3doaWNoKGdlbmVfbW9kdWxlX2RmX3NleCRpZCAlaW4lIGxpc3Rfb2ZfbXV0YW50X2dlbmVzKSxdKQpuYW1lcyhkZl9tdXRhbnRfZ2VuZV9tb2R1bGVzKVsxXSA8LSAiZ2VuZV9JRCIKCiMjIG1lcmdlIGRhdGFmcmFtZXMKZGZfbXV0YW50X2dlbmVfbW9kdWxlcyA8LSBtZXJnZShkZl9tdXRhbnRfZ2VuZV9tb2R1bGVzLCBkZl9tdXRhbnRfaWRzLCBieSA9ICJnZW5lX0lEIikKCiMjIEluc3BlY3QKZGZfbXV0YW50X2dlbmVfbW9kdWxlcwpgYGAKCnNvIG1vZHVsZXMgb2YgaW50ZXJlc3QgYXJlOgpgYGB7cn0KdGFibGUoZGZfbXV0YW50X2dlbmVfbW9kdWxlcyRtb2R1bGUpCmBgYAoKV2hpY2ggbW9kdWxlcyBkbyBvdGhlciBnZW5lcyBvZiBpbnRlcmVzdCBsaWUgaW4/OgpgYGB7cn0KIyMgbGFuZG1hcmsgZ2VuZXMgKGdlbmVzIG9mIGludGVyZXN0KQojIEFQMkcgLSBQQkFOS0EtMTQzNzUwMAojIEFQMiAtIFBCQU5LQS0wOTA5NjAwIC0gZnJvbSBwb3JhbiBwYXBlcgojIEFQMkctMiAtIFBCQU5LQS0xMDM0MzAwIAojIGNjcDIgLSAiUEJBTktBLTEzMTk1MDAiIC0gZmVtYWxlIDgyMAojIHAyNSAtICJQQkFOS0EtMDUxNTAwMCIgLSBmZW1hbGUKIyBwMjggLSAiUEJBTktBLTA1MTQ5MDAiIC0gZmVtYWxlCiMgY2NwMyAtICJQQkFOS0EtMTAzNTIwMCIgLSBmZW1hbGUgLSAgaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNTkwOTEyMi8KIyBuZWs0IC0gIlBCQU5LQS0wNjE2NzAwIiAtIGZlbWFsZQojIGFwMi1mZyAtICJQQkFOS0EtMTQxNTcwMCIgLSBmZW1hbGUgCiMgZG96aSAtICJQQkFOS0EtMTIxNzcwMCIgLSBmZW1hbGUKIyBNRzEgLSAiUEJBTktBLTA0MTYxMDAiIC0gbWFsZSA4MjAKIyBoYXAyIC0gIlBCQU5LQS0xMjEyNjAwIiAtIG1hbGUKIyBNQVBLMiAtICJQQkFOS0EtMDkzMzcwMCIgLSBtYWxlCiMgbmVrMSAtICJQQkFOS0EtMTQ0MzAwMCIgLSBtYWxlCiMgY2RwazQgLSAiUEJBTktBLTA2MTUyMDAiIC0gbWFsZQoKIyMgY3JlYXRlIGEgbGlzdCBvZiBsYW5kbWFyayBnZW5lcwpsaXN0X29mX2xhbmRtYXJrX2dlbmVzIDwtIGMoIlBCQU5LQS0xNDM3NTAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQQkFOS0EtMDkwOTYwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEJBTktBLTEwMzQzMDAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQQkFOS0EtMTMxOTUwMCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBCQU5LQS0wNTE1MDAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQQkFOS0EtMDUxNDkwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEJBTktBLTEwMzUyMDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBCQU5LQS0wNjE2NzAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQQkFOS0EtMTQxNTcwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEJBTktBLTEyMTc3MDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBCQU5LQS0wNDE2MTAwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEJBTktBLTEyMTI2MDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBCQU5LQS0wOTMzNzAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQQkFOS0EtMTQ0MzAwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEJBTktBLTA2MTUyMDAiKQoKbmFtZV9vZl9sYW5kbWFya19nZW5lcyA8LSBjKCJBUDItRyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFQMl9wb3JhbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFQMi1HMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImNjcDIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImNjcDMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5lazQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImFwMi1mZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRE9aSSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWcxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaGFwMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1hcGsyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJuZWsxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjZHBrNCIpCgojIyBtYWtlIGEgZGYKbmFtZV9vZl9sYW5kbWFya19nZW5lcyA8LSBkYXRhLmZyYW1lKCJnZW5lX25hbWUiID0gbmFtZV9vZl9sYW5kbWFya19nZW5lcywgImlkIiA9IGxpc3Rfb2ZfbGFuZG1hcmtfZ2VuZXMpCgojIyBtYWtlIGRhdGFmcmFtZQpkZl9sYW5kbWFya19nZW5lX21vZHVsZXMgPC0gZ2VuZV9tb2R1bGVfZGZfc2V4W3doaWNoKGdlbmVfbW9kdWxlX2RmX3NleCRpZCAlaW4lIGxpc3Rfb2ZfbGFuZG1hcmtfZ2VuZXMpLF0KCiMjIG1lcmdlIGRhdGFmcmFtZXMKZGZfbGFuZG1hcmtfZ2VuZV9tb2R1bGVzIDwtIG1lcmdlKGRmX2xhbmRtYXJrX2dlbmVfbW9kdWxlcywgbmFtZV9vZl9sYW5kbWFya19nZW5lcywgYnkgPSAiaWQiKQoKIyMgaW5zcGVjdApkZl9sYW5kbWFya19nZW5lX21vZHVsZXMKYGBgCmVucmljaG1lbnQgb2Ygc2NyZWVuIGhpdHMgaW4gbW9kdWxlcwpgYGB7cn0KIyMgcmVhZCBpbiBzY3JlZW4gaGl0cwpsaWJyYXJ5KCJyZWFkeGwiKQpzY3JlZW5faGl0cyA8LSByZWFkX2V4Y2VsKCIuLi9kYXRhL1NjcmVlbi9Nb2R1bGVzX0NsdXN0ZXJzX1BoZW5vdHlwZXMueGxzeCIpCgojIyBnZXQgb25seSBoaXRzCnNjcmVlbl9oaXRzX3NlbGVjdGVkIDwtIHNjcmVlbl9oaXRzW3doaWNoKHNjcmVlbl9oaXRzJGBHYW0gcGhlbm90eXBlIHNjcmVlbmAgPT0gIkJvdGgiIHwgc2NyZWVuX2hpdHMkYEdhbSBwaGVub3R5cGUgc2NyZWVuYCA9PSAiRmVtYWxlcyIgfCBzY3JlZW5faGl0cyRgR2FtIHBoZW5vdHlwZSBzY3JlZW5gID09ICJNYWxlcyIpLCBdIAoKIyMgZXh0cmFjdCBnZW5lIElEcwpnZW5lX2hpdHMgPC0gc2NyZWVuX2hpdHNfc2VsZWN0ZWQkYG5ldyBnZW5lIElEYAojIyBjaGFuZ2UgdGhlIHVuZGVyc2NvcmUgdG8gYSBkYXNoCmdlbmVfaGl0cyA8LSBnc3ViKCJfIiwgIi0iLCBnZW5lX2hpdHMpCgojIyBmaW5kIG91dCB3aGljaCBtb2R1bGVzIHRoZXkgYXJlIGluCmRmX2hpdHNfZ2VuZV9tb2R1bGVzIDwtIGdlbmVfbW9kdWxlX2RmX3NleFt3aGljaChnZW5lX21vZHVsZV9kZl9zZXgkaWQgJWluJSBnZW5lX2hpdHMpLF0KcHJpbnQoInNjcmVlbiBoaXRzIGJ5IG1vZHVsZSIpCnRhYmxlKGRmX2hpdHNfZ2VuZV9tb2R1bGVzJG1vZHVsZSkKCiMjIGdldCB0aGUgbnVtYmVyIGdlbmVzIHNjcmVlbmVkIGluIHRoYXQgbW9kdWxlCnNjcmVlbl9oaXRzX3NjcmVlbmVkIDwtIHNjcmVlbl9oaXRzW3doaWNoKHNjcmVlbl9oaXRzJGBHYW0gcGhlbm90eXBlIHNjcmVlbmAgPT0gIkJvdGgiIHwgc2NyZWVuX2hpdHMkYEdhbSBwaGVub3R5cGUgc2NyZWVuYCA9PSAiRmVtYWxlcyIgfCBzY3JlZW5faGl0cyRgR2FtIHBoZW5vdHlwZSBzY3JlZW5gID09ICJNYWxlcyIgfCBzY3JlZW5faGl0cyRgR2FtIHBoZW5vdHlwZSBzY3JlZW5gID09ICJOb25lIiB8IHNjcmVlbl9oaXRzJGBHYW0gcGhlbm90eXBlIHNjcmVlbmAgPT0gIm1hbGUgbm90IGVub3VnaCBwb3dlciIpLCBdIAojIyBleHRyYWN0IGdlbmUgSURzCmdlbmVzX3NjcmVlbmVkIDwtIHNjcmVlbl9oaXRzX3NjcmVlbmVkJGBuZXcgZ2VuZSBJRGAKIyMgY2hhbmdlIHRoZSB1bmRlcnNjb3JlIHRvIGEgZGFzaApnZW5lc19zY3JlZW5lZCA8LSBnc3ViKCJfIiwgIi0iLCBnZW5lc19zY3JlZW5lZCkKIyMgZmluZCBvdXQgd2hpY2ggbW9kdWxlcyB0aGV5IGFyZSBpbgpkZl9zY3JlZW5lZF9nZW5lX21vZHVsZXMgPC0gZ2VuZV9tb2R1bGVfZGZfc2V4W3doaWNoKGdlbmVfbW9kdWxlX2RmX3NleCRpZCAlaW4lIGdlbmVzX3NjcmVlbmVkKSxdCnByaW50KCJ0b3RhbCBnZW5lcyBzY3JlZW5lZCBpbiB0aGlzIG1vZHVsZSIpCnRhYmxlKGRmX3NjcmVlbmVkX2dlbmVfbW9kdWxlcyRtb2R1bGUpCgojIyBtYWtlIGEgdGFibGUgd2l0aCB0aGlzIGluZm8KcGNfc2NyZWVuZWQgPC0gZGF0YS5mcmFtZShoaXRzID0gdGFibGUoZGZfaGl0c19nZW5lX21vZHVsZXMkbW9kdWxlKSwgc2NyZWVuZWQgPSAgdGFibGUoZGZfc2NyZWVuZWRfZ2VuZV9tb2R1bGVzJG1vZHVsZSkpWywtM10KbmFtZXMocGNfc2NyZWVuZWQpIDwtIGMoIm1vZHVsZSIsICJoaXRzIiwgInNjcmVlbmVkIikKcGNfc2NyZWVuZWQkcGMgPC0gKHBjX3NjcmVlbmVkJGhpdHMgL3BjX3NjcmVlbmVkJHNjcmVlbmVkKSoxMDAKCiMjIHZpZXcKcGNfc2NyZWVuZWQKYGBgCgpET1pJLXJlZ3VsYXRlZCBnZW5lcwoKRmluZCBvdXQgaG93IG1hbnkgb2YgdGhlIGdlbmVzIGluIGVhY2ggbW9kdWxlIGhhcyBhIERPWkktcmVndWxhdGVkIGdlbmUKCmBgYHtyfQpET1pJX3JlZ3VsYXRlZF9nZW5lcyA8LQpyZWFkLmNzdihmaWxlID0gIi4uL2RhdGEvUmVmZXJlbmNlL0RPWklfcmVndWxhdGVkX2dlbmVzLmNzdiIsIGhlYWRlciA9IFRSVUUpCgojIyBleHRyYWN0IGdlbmUgSURzCmRvemlfZ2VuZXMgPC0gRE9aSV9yZWd1bGF0ZWRfZ2VuZXNbRE9aSV9yZWd1bGF0ZWRfZ2VuZXMkRE9aSV9yZWd1bGF0ZWQuID09ICJZRVMiLCBdJEdlbmVfSURfUEIKIyMgY2hhbmdlIHRoZSB1bmRlcnNjb3JlIHRvIGEgZGFzaApkb3ppX2dlbmVzIDwtIGdzdWIoIl8iLCAiLSIsIGRvemlfZ2VuZXMpCgojIyBmaW5kIG91dCB3aGljaCBtb2R1bGVzIHRoZXkgYXJlIGluCmRmX2RvemlfZ2VuZV9tb2R1bGVzIDwtIGdlbmVfbW9kdWxlX2RmX3NleFt3aGljaChnZW5lX21vZHVsZV9kZl9zZXgkaWQgJWluJSBkb3ppX2dlbmVzKSxdCnByaW50KCJkb3ppIGdlbmVzIGJ5IG1vZHVsZSIpCnRhYmxlKGRmX2RvemlfZ2VuZV9tb2R1bGVzJG1vZHVsZSkKYGBgCgoKIyMjIyBWaXN1YWxpc2UgbW9kdWxlIGV4cHJlc3Npb24KCnBsb3Qgb3V0IG1vZHVsZXMKYGBge3IsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQojIyBtYWtlIGFnZ3JlZ2F0ZWQgZGYgYWdhaW4gc28geW91IGNhbiBlZGl0IGl0CmFnZ19tYXQgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdCwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBjZWxsX2dyb3VwX2RmKQoKIyMgaCBjbHVzdCB0aGUgYWdncmVnYXRlZCBtYXRyaXgKbW9kdWxlX2RlbmRybyA8LSBoY2x1c3QoZGlzdChhZ2dfbWF0KSkKCiMjIHVzZSB0aGVzZSBjbHVzdGVycyB0byByZW9yZGVyIHRoZSBtb2R1bGVzCmdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUgPC0gZmFjdG9yKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUsIGxldmVscyA9IHJvdy5uYW1lcyhhZ2dfbWF0KVttb2R1bGVfZGVuZHJvJG9yZGVyXSkKCiMjIHBsb3QKVU1BUF9tb2R1bGVzIDwtIHBsb3RfY2VsbHMobW9ub2NsZS5vYmplY3QsIGdlbmVzPWdlbmVfbW9kdWxlX2RmX3NleCAlPiUgZmlsdGVyKG1vZHVsZSAlaW4lIGMoMToyMCkpLAogICAgICAgICAgIGNlbGxfc2l6ZSA9IDIsIAogICAgICAgICAgIHggPSAyLCB5ID0gMSwKICAgICAgICAgICBsYWJlbF9jZWxsX2dyb3Vwcz1GQUxTRSwKICAgICAgICAgICBzY2FsZV90b19yYW5nZSA9IFRSVUUsCiAgICAgICAgICAgc2hvd190cmFqZWN0b3J5X2dyYXBoPUZBTFNFKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhuYW1lID0gImV4cHJlc3Npb24iLCBvcHRpb24gPSAiQyIsIGFscGhhID0gMSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIGNvb3JkX2ZpeGVkKCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX3ZvaWQoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKQoKIyMgdmlldwpVTUFQX21vZHVsZXMKYGBgCnNhdmUKYGBge3J9Cmdnc2F2ZSgiLi4vaW1hZ2VzX3RvX2V4cG9ydC9HQ1NLT19zZXhicmFuY2hfdW1hcF9tb2R1bGVzLnBuZyIsIHBsb3QgPSBVTUFQX21vZHVsZXMsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDMwLCBoZWlnaHQgPSAzMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCmBgYAoKYGBge3J9CiMjIG1ha2UgYSBkYXRhZnJhbWUgb2YgZ2VuZXMgcGVyIG1vZHVsZQpnZW5lc19wZXJfbW9kdWxlIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSkpCgojIyBpbnNwZWN0CmdlbmVzX3Blcl9tb2R1bGUKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDEyfQojIyBBLiBQcmVwYXJhdGlvbiBvZiBkYXRhZnJhbWUKCiMjIHByZXBhcmUgY3VzdG9tIGRhdGFmcmFtZSBmb3IgYWxsIGNlbGxzIGJ5IG1vZHVsZXM6CmFnZ19tYXRfbm9fZ3JvdXAgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdCwgZ2VuZV9tb2R1bGVfZGZfc2V4KQoKIyMgQi4gYW5ub3RhdGlvbnMKCiMjIG1ha2UgYW4gYW5vdGF0aW9uCiMjIGFkZCBwdCB0byB0aGUgbW9ub2NsZSBvYmplY3QKbW9ub2NsZS5vYmplY3RAY29sRGF0YSRwdCA8LSBhcy5kYXRhLmZyYW1lKHBzZXVkb3RpbWUobW9ub2NsZS5vYmplY3QsIHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIpKQojIyBtYWtlIGFuIGFubm90YXRpb24gZGF0YWZyYW1lCmFubm9fbm9fZ3JvdXAgPC0gZGF0YS5mcmFtZShtb25vY2xlLm9iamVjdEBjb2xEYXRhJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUsIG1vbm9jbGUub2JqZWN0QGNvbERhdGEkcHQsIGFzLmZhY3Rvcihtb25vY2xlLm9iamVjdEBjb2xEYXRhJFByZWRpY3Rpb24uU3BlYXJtYW4uX0thc2lhKSwgcm93Lm5hbWVzID0gcm93bmFtZXMobW9ub2NsZS5vYmplY3RAY29sRGF0YSkpCm5hbWVzKGFubm9fbm9fZ3JvdXApIDwtIGMoIlNleCIsICJQc2V1ZG90aW1lIiwgIlJlYWxfdGltZV9wcmVkaWN0aW9uIikKCiMjIG1ha2UgYW5ub3RhdGlvbiBjb2xvdXJzCmFubm90YXRpb25fY29sb3VycyA8LSBsaXN0KFNleCA9IGMoTWFsZT0iIzAxNmMwMCIsIEZlbWFsZT0iI2E1MmIxZSIsIEJpcG90ZW50aWFsID0gIiNmZmU0MDAiLCBBc2V4dWFsID0gIiMwMDUyYzUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgUHNldWRvdGltZSA9IHBsYXNtYSgxMiwgZGlyZWN0aW9uID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFJlYWxfdGltZV9wcmVkaWN0aW9uID0gYygiMCIgPSB2aXJpZGlzKDgsIGRpcmVjdGlvbiA9IDEpWzFdICwiMSIgPSAgdmlyaWRpcyg4LCBkaXJlY3Rpb24gPSAxKVsyXSAsIjQiID0gdmlyaWRpcyg4LCBkaXJlY3Rpb24gPSAxKVszXSAsIjYiID0gdmlyaWRpcyg4LCBkaXJlY3Rpb24gPSAxKVs0XSAsIjgiID0gdmlyaWRpcyg4LCBkaXJlY3Rpb24gPSAxKVs1XSAgLCIxMiIgID0gdmlyaWRpcyg4LCBkaXJlY3Rpb24gPSAxKVs2XSAgLCIxOCIgPSB2aXJpZGlzKDgsIGRpcmVjdGlvbiA9IDEpWzddICAsIjI0IiA9IHZpcmlkaXMoOCwgZGlyZWN0aW9uID0gMSlbOF0pKQoKIyMgY2hhbmdlIHRoZSBvcmRlciBvZiB0aGUgY29scyAoY2VsbHMpIGluIGRhdGEgZnJhbWUKY29sLm9yZGVyIDwtIHJvd25hbWVzKGFubm9fbm9fZ3JvdXBbd2l0aChhbm5vX25vX2dyb3VwLCBvcmRlcihTZXgsIFBzZXVkb3RpbWUpKSwgXSkKYWdnX21hdF9ub19ncm91cCA8LSBhZ2dfbWF0X25vX2dyb3VwWyxjb2wub3JkZXJdCgojIyByZW9yZGVyIHRoZSByb3dzIChnZW5lIG1vZHVsZXMpIGluIHRoZSBkYXRhIGZyYW1lIHNvIHRoZXkgYXJlIGluIHB0IG9yZGVyCiMjIGRlZmluZSB0aGUgb3JkZXIgdmlzdWFsbHkgYW5kIHVzaW5nIHRoZSBjbHVzdGVycyBvcmlnaW5hbGx5IHByb2R1Y2VkCnJvdy5vcmRlciA8LSBjKCI3IiwgIjgiLCAiNiIsICIzIiwgIjEyIiwiNCIsICIxNiIsICIxNSIsICIxMCIsICIxIiwgIjEzIiwgIjE3IiwgIjIiLCAiMTgiLCAiMTEiLCAiMTQiLCAiOSIsICI1IikKIyMgcmVvcmRlciB1c2luZyBuZXcgb3JkZXIKYWdnX21hdF9ub19ncm91cCA8LSBhZ2dfbWF0X25vX2dyb3VwW3Jvdy5vcmRlciwgXQoKIyMgZm9yIGN1dHMgaW4gY29sdW1ucyAtIHVzZWQgbGF0ZXIgdG8gY291bnQgbnVtYmVyIG9mIGNlbGxzIGluIGVhY2ggY2F0CmRmX21ldGEgPC0gYXMuZGF0YS5mcmFtZShtb25vY2xlLm9iamVjdEBjb2xEYXRhKQpmZW1hbGVfY2VsbHMgPC0gcm93bmFtZXMoZGZfbWV0YVt3aGljaChkZl9tZXRhJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUgPT0gIkZlbWFsZSIpLCBdKQptYWxlX2NlbGxzIDwtIHJvd25hbWVzKGRmX21ldGFbd2hpY2goZGZfbWV0YSRjbHVzdGVyX2NvbG91cnNfZmlndXJlID09ICJNYWxlIiksIF0pCmJpX2NlbGxzIDwtIHJvd25hbWVzKGRmX21ldGFbd2hpY2goZGZfbWV0YSRjbHVzdGVyX2NvbG91cnNfZmlndXJlID09ICJCaXBvdGVudGlhbCIpLCBdKQphc2V4X2NlbGxzIDwtIHJvd25hbWVzKGRmX21ldGFbd2hpY2goZGZfbWV0YSRjbHVzdGVyX2NvbG91cnNfZmlndXJlID09ICJBc2V4dWFsIiksIF0pCnJtKGRmX21ldGEpCgojIyBhZGQgbW9kdWxlIGFuZCB0aGUgbnVtYmVyIG9mIGNlbGxzIHRvIHRoZSByb3cKIyMgY2hhbmdlIG5hbWVzIGZvciByb3cgbmFtZXMgdG8gaW5jbHVkZSAibW9kdWxlICIgYXQgdGhlIGJlZ2luaW5nIG9mIHRoZW0KbGFiZWxzLnJvdyA8LSBzdHJpbmdyOjpzdHJfYygiTW9kdWxlICIsIHJvdy5uYW1lcyhhZ2dfbWF0X25vX2dyb3VwKSkKIyMgcmVvcmRlciBmcmVxdWVuY3kgc28gdGhhdCBpdCBpcyBtYXRjaGluZyBvdXIgbWF0cml4CmdlbmVzX3Blcl9tb2R1bGVfb3JkZXJlZCA8LSBnZW5lc19wZXJfbW9kdWxlW21hdGNoKHJvdy5uYW1lcyhhZ2dfbWF0X25vX2dyb3VwKSwgZ2VuZXNfcGVyX21vZHVsZSRWYXIxKSwgXQojIyBhZGQgbnVtYmVyIG9mIGNlbGxzIHRvIHRoZSByb3duYW1lcyBmb3IgdGhlIG1vZHVsZQpmb3IoaSBpbiBzZXFfYWxvbmcoZ2VuZXNfcGVyX21vZHVsZV9vcmRlcmVkJEZyZXEpKXsKICBsYWJlbHMucm93W2ldIDwtIHN0cmluZ3I6OnN0cl9jKGxhYmVscy5yb3dbaV0sIiAobiA9ICIgLGdlbmVzX3Blcl9tb2R1bGVfb3JkZXJlZCRGcmVxW2ldLCAiKSIpCn0KCiMjIEMuIFBsb3R0aW5nCgojIyBwbG90CmhlYXRtYXBfbWFpbiA8LSBwaGVhdG1hcDo6cGhlYXRtYXAoYWdnX21hdF9ub19ncm91cCwgCiAgICAgICAgICAgICAgICAgICAjc2NhbGU9InJvdyIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgIyMgb3RoZXJzOiB3YXJkLkQyLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJjb21wbGV0ZSIsCiAgICAgICAgICAgICAgICAgICBzaG93X2NvbG5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBsYWJlbHNfcm93ID0gbGFiZWxzLnJvdywKICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDE1LAogICAgICAgICAgICAgICAgICAgZm9udHNpemUgPSAxNSwKICAgICAgICAgICAgICAgICAgIGdhcHNfY29sID0gYyhsZW5ndGgoYXNleF9jZWxscyksIGxlbmd0aChjKGFzZXhfY2VsbHMsYmlfY2VsbHMpKSwgbGVuZ3RoKGMoYXNleF9jZWxscyxiaV9jZWxscyxmZW1hbGVfY2VsbHMpKSksCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm9fbm9fZ3JvdXAsIAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uX2NvbG91cnMsIAogICAgICAgICAgICAgICAgICAgY3V0cmVlX3Jvd3MgPSA2KQoKIyMgdmlldwpoZWF0bWFwX21haW4KYGBgCnNhdmUKYGBge3J9Cmdnc2F2ZSgiLi4vaW1hZ2VzX3RvX2V4cG9ydC9HQ1NLT19zZXhicmFuY2hfaGVhdG1hcC5wbmciLCBwbG90ID0gaGVhdG1hcF9tYWluLCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAyNywgaGVpZ2h0ID0gMjAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCiMjIyMgVmlzdWFsaXNlIHRoZSBleHByZXNzaW9uIG9mIHNlbGVjdCBnZW5lcyBvdmVyIHBzZXVkb3RpbWUKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gMTB9CiMjIGxhbmRtYXJrIGdlbmVzIChnZW5lcyBvZiBpbnRlcmVzdCkKIyBBUDJHIC0gUEJBTktBLTE0Mzc1MDAKIyBBUDIgLSBQQkFOS0EtMDkwOTYwMCAtIGZyb20gcG9yYW4gcGFwZXIKIyBBUDJHLTIgLSBQQkFOS0EtMTAzNDMwMCAKI2xpc3Rfb2ZfbXV0YW50X2dlbmVzIDwtIGMoIlBCQU5LQS0wODI4MDAwIiwgIlBCQU5LQS0xMzAyNzAwIiwgIlBCQU5LQS0xNDQ3OTAwIiwgIlBCQU5LQS0wMTAyNDAwIiwgIlBCQU5LQS0wNzE2NTAwIiwgIlBCQU5LQS0xNDM1MjAwIiwgIlBCQU5LQS0xNDE4MTAwIiwgIlBCQU5LQS0xMTQ0ODAwIiwgIlBCQU5LQS0wOTAyMzAwIiwgIlBCQU5LQS0wNDEzNDAwIiwgIlBCQU5LQS0xNDU0ODAwIikKCiMjIGRlZmluZSBnZW5lcyB0byBwbG90Cmxpc3Rfb2ZfZ2VuZXNfb2ZfaW50ZXJlc3QgPC0gYygiUEJBTktBLTAxMDI0MDAiLCAiUEJBTktBLTA0MTM0MDAiLCAiUEJBTktBLTA3MTY1MDAiLCAiUEJBTktBLTA4MjgwMDAiLCAiUEJBTktBLTA5MDIzMDAiLCAiUEJBTktBLTExNDQ4MDAiLCAiUEJBTktBLTEzMDI3MDAiLCAiUEJBTktBLTE0MTgxMDAiLCAiUEJBTktBLTE0MzUyMDAiLCAiUEJBTktBLTE0NDc5MDAiLCAiUEJBTktBLTE0NTQ4MDAiLCAiUEJBTktBLTE0Mzc1MDAiLCAiUEJBTktBLTEzMTk1MDAiLCAiUEJBTktBLTA0MTYxMDAiLCAiUEJBTktBLTEwMzQzMDAiKQojIyBhZGQgbmFtZXMKbmFtZXNfb2ZfZ2VuZXNfb2ZfaW50ZXJlc3QgPC0gYygiR0NTS08tMiIsICJHQ1NLTy0xMCIsICJHQ1NLTy0xOSIsICJHQ1NLTy0zIiwgIkdDU0tPLTEzIiwgIkdDU0tPLTI4IiwgIkdDU0tPLW9vbSIsICJHQ1NLTy0xNyIsICJHQ1NLTy0yMCIsICJHQ1NLTy0yOSIsICJHQ1NLTy0yMSIsICJBUDItRyIsICJDQ1AyIiwgIk1HMSIsICJBUDItRzIiKQoKIyNtYWtlIGRmIGZvciBnZW5lcyBvZiBpbnRlcmVzdApnZW5lc19vZl9pbnRlcmVzdCA8LSBkYXRhLmZyYW1lKGdlbmUgPSBsaXN0X29mX2dlbmVzX29mX2ludGVyZXN0LCBncm91cCA9IGMoMTpsZW5ndGgobGlzdF9vZl9nZW5lc19vZl9pbnRlcmVzdCkpLCBuYW1lID0gbmFtZXNfb2ZfZ2VuZXNfb2ZfaW50ZXJlc3QpCiMjIHJlb3JkZXIKI2dlbmVzX29mX2ludGVyZXN0IDwtIGdlbmVzX29mX2ludGVyZXN0W21hdGNoKGMoIkFQMi1HIiwgIkNDUDIiLCAiR0NTS08tMjEiLCAiR0NTS08tMTciLCAiR0NTS08tMiIsICJNRzEiLCAiR0NTS08tMjAiLCAiR0NTS08tMyIsICJHQ1NLTy1vb20iLCAiR0NTS08tMjkiLCAiR0NTS08tMTAiLCAiR0NTS08tMjgiLCAiR0NTS08tMTkiLCAiR0NTS08tMTMiKSwgZ2VuZXNfb2ZfaW50ZXJlc3QkbmFtZSksIF0KCiMjIHByZXBhcmUgY3VzdG9tIGRhdGFmcmFtZSBmb3IgYWxsIGNlbGxzIGJ5IG1vZHVsZXM6CmFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdCwgZ2VuZXNfb2ZfaW50ZXJlc3RbLDE6Ml0pCgojIyByZW9yZGVyIHVzaW5nIG5ldyBvcmRlcgphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3RbLGNvbC5vcmRlcl0KCiMjIHBsb3QKaGVhdG1hcF9wbG90IDwtIHBoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0LCAKICAgICAgICAgICAgICAgICAgICNzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIHNob3dfY29sbmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGxhYmVsc19yb3cgPSBhcy5jaGFyYWN0ZXIoZ2VuZXNfb2ZfaW50ZXJlc3RbLDNdKSwKICAgICAgICAgICAgICAgICAgIGdhcHNfY29sID0gYyhsZW5ndGgoYXNleF9jZWxscyksIGxlbmd0aChjKGFzZXhfY2VsbHMsYmlfY2VsbHMpKSwgbGVuZ3RoKGMoYXNleF9jZWxscyxiaV9jZWxscyxmZW1hbGVfY2VsbHMpKSksCiAgICAgICAgICAgICAgICAgICAjZ2Fwc19yb3cgPSBjKDEsIDYpLAogICAgICAgICAgICAgICAgICAgY3V0cmVlX3Jvd3MgPSAyLAogICAgICAgICAgICAgICAgICAgIyMgdHJ5aW5nIHRvIGZpeCBsZWdlbmQgaXNzdWUgaGVyZQogICAgICAgICAgICAgICAgICAgI2ZvbnRzaXplX3JvdyA9IDEwLAogICAgICAgICAgICAgICAgICAgI2ZvbnRzaXplX2NvbCA9IDMsCiAgICAgICAgICAgICAgICAgICAjY2VsbGhlaWdodD0zLCAKICAgICAgICAgICAgICAgICAgICNjZWxsd2lkdGggPSAzLAogICAgICAgICAgICAgICAgICAgbGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm9fbm9fZ3JvdXAsIAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uX2NvbG91cnMKICAgICAgICAgICAgICAgICAgICkKCmhlYXRtYXBfcGxvdApgYGAKCmxvb2sgYXQgc29tZSBvZiB0aGUgIm1vZHVsZSIgZ2VuZXMgbm93IHRvbwoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMH0KIyMgbGFuZG1hcmsgZ2VuZXMgKGdlbmVzIG9mIGludGVyZXN0KQojIEFQMkcgLSBQQkFOS0EtMTQzNzUwMAojIEFQMiAtIFBCQU5LQS0wOTA5NjAwIC0gZnJvbSBwb3JhbiBwYXBlcgojIEFQMkctMiAtIFBCQU5LQS0xMDM0MzAwIAojbGlzdF9vZl9tdXRhbnRfZ2VuZXMgPC0gYygiUEJBTktBLTA4MjgwMDAiLCAiUEJBTktBLTEzMDI3MDAiLCAiUEJBTktBLTE0NDc5MDAiLCAiUEJBTktBLTAxMDI0MDAiLCAiUEJBTktBLTA3MTY1MDAiLCAiUEJBTktBLTE0MzUyMDAiLCAiUEJBTktBLTE0MTgxMDAiLCAiUEJBTktBLTExNDQ4MDAiLCAiUEJBTktBLTA5MDIzMDAiLCAiUEJBTktBLTA0MTM0MDAiLCAiUEJBTktBLTE0NTQ4MDAiKQoKIyMgZGVmaW5lIGdlbmVzIHRvIHBsb3QKbGlzdF9vZl9nZW5lc19vZl9pbnRlcmVzdCA8LSBjKCJQQkFOS0EtMTQ1NDAwMCIsICJQQkFOS0EtMTM1NDAwMCIpCiMjIGFkZCBuYW1lcwpuYW1lc19vZl9nZW5lc19vZl9pbnRlcmVzdCA8LSBjKCJHeXJCIiwgIkRCUjEiKQoKIyNtYWtlIGRmIGZvciBnZW5lcyBvZiBpbnRlcmVzdApnZW5lc19vZl9pbnRlcmVzdCA8LSBkYXRhLmZyYW1lKGdlbmUgPSBsaXN0X29mX2dlbmVzX29mX2ludGVyZXN0LCBncm91cCA9IGMoMTpsZW5ndGgobGlzdF9vZl9nZW5lc19vZl9pbnRlcmVzdCkpLCBuYW1lID0gbmFtZXNfb2ZfZ2VuZXNfb2ZfaW50ZXJlc3QpCiMjIHJlb3JkZXIKI2dlbmVzX29mX2ludGVyZXN0IDwtIGdlbmVzX29mX2ludGVyZXN0W21hdGNoKGMoIkFQMi1HIiwgIkNDUDIiLCAiR0NTS08tMjEiLCAiR0NTS08tMTciLCAiR0NTS08tMiIsICJNRzEiLCAiR0NTS08tMjAiLCAiR0NTS08tMyIsICJHQ1NLTy1vb20iLCAiR0NTS08tMjkiLCAiR0NTS08tMTAiLCAiR0NTS08tMjgiLCAiR0NTS08tMTkiLCAiR0NTS08tMTMiKSwgZ2VuZXNfb2ZfaW50ZXJlc3QkbmFtZSksIF0KCiMjIHByZXBhcmUgY3VzdG9tIGRhdGFmcmFtZSBmb3IgYWxsIGNlbGxzIGJ5IG1vZHVsZXM6CmFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdCwgZ2VuZXNfb2ZfaW50ZXJlc3RbLDE6Ml0pCgojIyByZW9yZGVyIHVzaW5nIG5ldyBvcmRlcgphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3RbLGNvbC5vcmRlcl0KCiMjIHBsb3QKaGVhdG1hcF9wbG90IDwtIHBoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0LCAKICAgICAgICAgICAgICAgICAgICNzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIHNob3dfY29sbmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGxhYmVsc19yb3cgPSBhcy5jaGFyYWN0ZXIoZ2VuZXNfb2ZfaW50ZXJlc3RbLDNdKSwKICAgICAgICAgICAgICAgICAgIGdhcHNfY29sID0gYyhsZW5ndGgoYXNleF9jZWxscyksIGxlbmd0aChjKGFzZXhfY2VsbHMsYmlfY2VsbHMpKSwgbGVuZ3RoKGMoYXNleF9jZWxscyxiaV9jZWxscyxmZW1hbGVfY2VsbHMpKSksCiAgICAgICAgICAgICAgICAgICAjZ2Fwc19yb3cgPSBjKDEsIDYpLAogICAgICAgICAgICAgICAgICAgY3V0cmVlX3Jvd3MgPSAyLAogICAgICAgICAgICAgICAgICAgIyMgdHJ5aW5nIHRvIGZpeCBsZWdlbmQgaXNzdWUgaGVyZQogICAgICAgICAgICAgICAgICAgI2ZvbnRzaXplX3JvdyA9IDEwLAogICAgICAgICAgICAgICAgICAgI2ZvbnRzaXplX2NvbCA9IDMsCiAgICAgICAgICAgICAgICAgICAjY2VsbGhlaWdodD0zLCAKICAgICAgICAgICAgICAgICAgICNjZWxsd2lkdGggPSAzLAogICAgICAgICAgICAgICAgICAgbGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm9fbm9fZ3JvdXAsIAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uX2NvbG91cnMKICAgICAgICAgICAgICAgICAgICkKCmhlYXRtYXBfcGxvdApgYGAKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCk1ha2UgYW5ub3RhdGlvbnMgdG8gYWRkIHRvIHRoZSBoZWF0bWFwCmBgYHtyfQojIyBjaGFuZ2UgbmFtZXMgZm9yIHJvdyBuYW1lcyB0byBpbmNsdWRlICJtb2R1bGUgIiBhdCB0aGUgYmVnaW5pbmcgb2YgdGhlbQpyb3cubmFtZXMoYWdnX21hdCkgPC0gc3RyaW5ncjo6c3RyX2MoIk1vZHVsZSAiLCByb3cubmFtZXMoYWdnX21hdCkpCgojIyBhZGQgbnVtYmVyIG9mIGNlbGxzIHRvIHRoZSByb3duYW1lcyBmb3IgdGhlIG1vZHVsZQpmb3IoaSBpbiBzZXFfYWxvbmcoZ2VuZXNfcGVyX21vZHVsZSRGcmVxKSl7CiAgcm93Lm5hbWVzKGFnZ19tYXQpW2ldIDwtIHN0cmluZ3I6OnN0cl9jKHJvdy5uYW1lcyhhZ2dfbWF0KVtpXSwiIChuID0gIiAsZ2VuZXNfcGVyX21vZHVsZSRGcmVxW2ldLCAiKSIpCn0KCiMjIGNyZWF0ZSBhbm5vdGF0aW9uIG9mIGNsdXN0ZXJzIGZvciBwaGVhdG1hcDoKY2x1c3Rlcl9hbm5vIDwtIGRhdGEuZnJhbWUoY2x1c3RlciA9IHVuaXF1ZShjb2xEYXRhKG1vbm9jbGUub2JqZWN0KSRzZXVyYXRfY2x1c3RlcnMpKQpyb3cubmFtZXMoY2x1c3Rlcl9hbm5vKSA8LSBjbHVzdGVyX2Fubm8kY2x1c3RlcgoKIyMgY2x1c3RlcnMgd2VyZSBkZWZpbmVkIGVhcmxpZXIgYXM6Cm1hbGVfY2x1c3RlcnMgPC0gYygiMTMiLCAiNSIsICIxMSIsICIyNSIsICIxIiwgIjE3IiwgIjEwIiwgIjI0IiwgIjE0IiwgIjI3IiwgIjE5IikKZmVtYWxlX2NsdXN0ZXJzIDwtIGMoIjE2IiwgIjIyIiwgIjIzIiwgIjE1IiwgIjIxIiwgIjMwIiwgIjQiLCAiMyIsICIxOCIsICI3IiwgIjgiLCAiNiIsICIyMCIsICIxMiIsICIyNiIpCmFzZXhfY2x1c3RlcnMgPC0gYygiMCIsICI5IiwgIjI4IiwgIjIiLCAiMjkiKQoKIyMgYWRkIGlkZW50aXRpZXMgdG8gdGhlIGNvbHVtbgpjbHVzdGVyX2Fubm8kZ3JvdXAgPC0gTkEKY2x1c3Rlcl9hbm5vJGdyb3VwW3doaWNoKGNsdXN0ZXJfYW5ubyRjbHVzdGVyICVpbiUgYXNleF9jbHVzdGVycyldIDwtICJBc2V4dWFsIgpjbHVzdGVyX2Fubm8kZ3JvdXBbd2hpY2goY2x1c3Rlcl9hbm5vJGNsdXN0ZXIgJWluJSBtYWxlX2NsdXN0ZXJzKV0gPC0gIk1hbGUiCmNsdXN0ZXJfYW5ubyRncm91cFt3aGljaChjbHVzdGVyX2Fubm8kY2x1c3RlciAlaW4lIGZlbWFsZV9jbHVzdGVycyldIDwtICJGZW1hbGUiCmNsdXN0ZXJfYW5ubyA8LSBjbHVzdGVyX2Fubm9bICwgMiwgZHJvcCA9IEZBTFNFXQpjbHVzdGVyX2Fubm8KCiMjIGFkZCBtZWRpYW4gcHNldWRvdGltZSBwZXIgY2x1c3RlcgojIyBoZWxwIGhlcmU6CiMjIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzU0MzYwODU1L2NhbGN1bGF0ZS1tZWFuLWZvci1jb2x1bW4tZ3JvdXBlZC1ieS12YWx1ZXMtb2YtdHdvLW90aGVyLWNvbHVtbnMKIyMgbWFrZSBzdWJzZXR0ZWQgZGF0YWZyYW1lCmRmX21lZGlhbl9wdCA8LSBtZXRhX2RhdGFfZGZbICxjKCJwdCIsICJzZXVyYXRfY2x1c3RlcnMiKV0KIyMgYXBwbHkgYWNyb3NzIGRhdGFmcmFtZSB0byBnZXQgbWVkaWFuCm1lYW4uZGYxIDwtIHRhcHBseShkZl9tZWRpYW5fcHQkcHQsIGxpc3QoZGZfbWVkaWFuX3B0JHNldXJhdF9jbHVzdGVycyksIG1lZGlhbikKbWVhbi5kZjIgPC0gYXMuZGF0YS5mcmFtZShhcy50YWJsZShtZWFuLmRmMSkpCm5hbWVzKG1lYW4uZGYyKSA8LSBjKCJzZXVyYXRfY2x1c3RlcnMiLCAicHRfTWVkaWFuIikKcm93bmFtZXMobWVhbi5kZjIpIDwtIG1lYW4uZGYyJHNldXJhdF9jbHVzdGVycwojIyB0byBtYWtlIGVhY2ggdmFsdWUgaGF2ZSB0aGUgbWVhbiBpbiB0aGUgT0cgZGF0YWZyYW1lCiNtZXJnZShkZl9tZWRpYW5fcHQsIG1lYW4uZGYyKQojIyBhZGQgdG8gYW5ub3RhdGlvbiBkYXRhZnJhbWUKY2x1c3Rlcl9hbm5vIDwtIG1lcmdlKGNsdXN0ZXJfYW5ubywgbWVhbi5kZjIsIGJ5PTApCgojIyBhZGQgcm93bmFtZXMgdG8gZGF0YWZyYW1lCnJvd25hbWVzKGNsdXN0ZXJfYW5ubykgPC0gY2x1c3Rlcl9hbm5vJFJvdy5uYW1lcwojIyBzdWJzZXQgdG8gaGF2ZSBvbmx5IGluZm8gb2YgaW50ZXJlc3QKY2x1c3Rlcl9hbm5vIDwtIGNsdXN0ZXJfYW5ub1ssYygyLDQpXQpuYW1lcyhjbHVzdGVyX2Fubm8pIDwtIGMoIklkZW50aXR5IiwgIk1lZGlhbl9Qc2V1ZG90aW1lX29mX0NsdXN0ZXIiKQpgYGAKCiMjIyMgV1QgY2VsbHMgYnkgbW9kdWxlcyBvdmVyIHB0IChjZW50cmFsIHBhbmVsKQoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTJ9CiMjIG1ha2UgYW5ub3RhdGlvbiBjb2xvdXJzCmFubm90YXRpb25fY29sb3VycyA8LSBsaXN0KElkZW50aXR5ID0gYyhNYWxlPSIjMDE2YzAwIiwgRmVtYWxlPSIjYTUyYjFlIiwgQXNleHVhbD0gIiMwMDUyYzUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgTWVkaWFuX1BzZXVkb3RpbWVfb2ZfQ2x1c3RlciA9IG1hZ21hKDEyLCBkaXJlY3Rpb24gPSAxKSkKCiMjIHJlb3JkZXIgdGhlIGxldmVscwojIyBtYWtlIGRmIG9mIGRhdGEKYWdnX21hdF9kZiA8LSBhcy5kYXRhLmZyYW1lKGFnZ19tYXQpCiMjIHJlbW92ZSBsZXZlbHMgaW4gbXlfbGV2ZWxzIHRoYXQgYXJlIG5vdCBwcmVzZW50IGhlcmUgLSBpLmUuIGNsdXN0ZXJzIHRoYXQgYXJlIG1pc3NpbmcgYmVjYXVzZSB0aGV5IGFyZSBub3QgcmVwcmVzZW50ZWQgaW4gdGhlIDEwWCBkYXRhCm15X2xldmVsc18xMHhfZGF0YSA8LSBteV9sZXZlbHNfc2V4W3doaWNoKG15X2xldmVsc19zZXggJWluJSBjb2xuYW1lcyhhZ2dfbWF0X2RmKSldCiMjIHNvcnQgdGhlIHZhbHVlcwphZ2dfbWF0X2RmIDwtIGFnZ19tYXRfZGZbICwobWF0Y2gobXlfbGV2ZWxzXzEweF9kYXRhLCBjb2xuYW1lcyhhZ2dfbWF0X2RmKSkpXQoKIyMgb3JkZXIgCiNjbHVzdGVyX2Fubm8gPC0gY2x1c3Rlcl9hbm5vWyhtYXRjaChteV9sZXZlbHNfMTB4X2RhdGEsIHJvd25hbWVzKGNsdXN0ZXJfYW5ubykpKSwgXQoKIyMgcmVvcmRlciBjb2x1bW5zIAojIyBmaXJzdCwgb3JkZXIgdGhlIGFubm90YXRpb24KY2x1c3Rlcl9hbm5vIDwtIGNsdXN0ZXJfYW5ub1t3aXRoKGNsdXN0ZXJfYW5ubywgb3JkZXIoSWRlbnRpdHksIE1lZGlhbl9Qc2V1ZG90aW1lX29mX0NsdXN0ZXIpKSxdCgojIyByZW1vdmUgdGhlIE5BcyBmcm9tIHRoaXMKY2x1c3Rlcl9hbm5vIDwtIGNsdXN0ZXJfYW5ub1tjb21wbGV0ZS5jYXNlcyhjbHVzdGVyX2Fubm8pLF0KCmFnZ19tYXRfZGYgPC0gYWdnX21hdF9kZlsgLG1hdGNoKHJvd25hbWVzKGNsdXN0ZXJfYW5ubyksIGNvbG5hbWVzKGFnZ19tYXRfZGYpKV0KCiMjIHBsb3QgaGVhdG1hcApwaGVhdG1hcDo6cGhlYXRtYXAoYWdnX21hdF9kZiwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLCAKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sID0gY2x1c3Rlcl9hbm5vLCAKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbl9jb2xvdXJzLCAKICAgICAgICAgICAgICAgICAgIGN1dHJlZV9yb3dzID0gMTIpCgojLCBnYXBzX2NvbCA9IGMoMjgsMjksMzcpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMH0KI3Jvdy5uYW1lcyhhZ2dfbWF0KSA8LSBmYWN0b3Iocm93Lm5hbWVzKGFnZ19tYXQpLCBsZXZlbHMgPSByb3cubmFtZXMoYWdnX21hdClbbW9kdWxlX2RlbmRybyRvcmRlcl0pCgojIyBwbG90IGhlYXRtYXAKI3BoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X2RmLCAKICAjICAgICAgICAgICAgICAgICAgc2NhbGU9ImNvbHVtbiIsCiAgIyAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgIyAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IG1vZHVsZV9kZW5kcm8sCiAgIyAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgIyAgICAgICAgICAgICAgICAgIGN1dHJlZV9yb3dzID0gNSwKICAjICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBjbHVzdGVyX2Fubm8sIAogICMgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycykgKyAKICAjIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCkFsbCBDZWxscwoKCgojIyMgUGxvdCBzcGVjaWZpYyBnZW5lcyBvZiBpbnRlcmVzdAoKCgpTaWRlIHBsb3RzCgpjb25zdHJ1Y3QgbmV3IGRhdGFmcmFtZXMgZm9yIHRoZSBjZWxscyBmcm9tIG11dGFudHMgZm9yIGVhY2ggc2V4CmBgYHtyfQojIyBUaGUgb3JpZ2luYWwgb2JqZWN0IGNvbnRhaW5zIGFsbCBjZWxscywgd2UganVzdCB3YW50IHdpbGQtdHlwZSBzbyBsZXQncyBzdWJzZXQgb3V0IGdlbmVfbW9kdWxlX2RmIGFuZCBjZWxsX2dyb3VwX2RmIGFjY29yZGluZ2x5CgojIyBtYWxlCiMjIHN1YnNldCBvdXQgb25seSBtYWxlIGFuZCBwcmUgZGV0ZXJtaW5hdGlvbiBjZWxscwptYWxlX2NlbGxzIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkYXRfc2V4ID09ICJtYWxlIiksIF0KIyMgdGFrZSBmb3J3YXJkIG9ubHkgc21hcnQtc2VxMgptYWxlX2NlbGxzIDwtIG1hbGVfY2VsbHNbd2hpY2gobWFsZV9jZWxscyRleHBlcmltZW50ID09ICJtdXRhbnRzIiksIF0KIyMgZ2V0IGNlbGwgbmFtZXMKbWFsZV9jZWxscyA8LSByb3duYW1lcyhtYWxlX2NlbGxzKQojIyBzdWJzZXQgU2V1cmF0IG9iamVjdCB0byBjb250YWluIGNlbGxzIG9mIGludGVyZXN0ICAKbWFsZS5zZXVyYXQub2JqZWN0IDwtIFN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gbWFsZV9jZWxscykKIyMgbWFrZSBuZXcgY291bnRzIGFuZCBwaGVubzoKZGF0YSA8LSBhcyhhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKG1hbGUuc2V1cmF0Lm9iamVjdCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikpLCAnc3BhcnNlTWF0cml4JykKcGQgPC0gZGF0YS5mcmFtZShtYWxlLnNldXJhdC5vYmplY3RAbWV0YS5kYXRhKQojIyBrZWVwIG9ubHkgdGhlIGNvbHVtbnMgdGhhdCBhcmUgcmVsZXZhbnQKI3BEYXRhIDwtIHBkICU+JSBzZWxlY3Qob3JpZy5pZGVudCwgbkNvdW50X1JOQSwgbkZlYXR1cmVfUk5BKQpmRGF0YSA8LSBkYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IHJvdy5uYW1lcyhkYXRhKSwgcm93Lm5hbWVzID0gcm93Lm5hbWVzKGRhdGEpKQojIyBDb25zdHJ1Y3QgbW9ub2NsZSBjZHMKbWFsZS5tb25vY2xlLm9iamVjdCA8LSBuZXdfY2VsbF9kYXRhX3NldChleHByZXNzaW9uX2RhdGEgPSBkYXRhLCBjZWxsX21ldGFkYXRhID0gcGQsIGdlbmVfbWV0YWRhdGEgPSBmRGF0YSkKIyMgcHJlcHJvY2VzcwptYWxlLm1vbm9jbGUub2JqZWN0ID0gcHJlcHJvY2Vzc19jZHMobWFsZS5tb25vY2xlLm9iamVjdCwgbnVtX2RpbSA9IDUwLCBub3JtX21ldGhvZCA9ICJub25lIikgIAojIyBtYWtlIGEgbmV3IGRhdGFmcmFtZSBmb3IgY2VsbCBncm91cHMgLSBpdCBpcyBjcnVjaWFsIHRvIHJlZmFjdG9yIG90aGVyd2lzZSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uIHRoaW5rcyBpdCdzIG91dCBvZiBib3VuZHMgIAojbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGRhdGEuZnJhbWUoY2VsbD1hcy5jaGFyYWN0ZXIoZmFjdG9yKG1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkKSksIGNlbGxfZ3JvdXA9ZmFjdG9yKG1hbGVfY2VsbF9ncm91cF9kZiRwdF9iaW4pKSAgCiMjIGFnZ3JlZ2F0ZSBleHByZXNzaW9uCm1hbGVfYWdnX21hdCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1hbGUubW9ub2NsZS5vYmplY3QsIGdlbmVfbW9kdWxlX2RmX3NleCwgZXhjbHVkZS5uYSA9IEZBTFNFKQoKIyMgZmVtYWxlCiMjIHN1YnNldCBvdXQgb25seSBtYWxlIGFuZCBwcmUgZGV0ZXJtaW5hdGlvbiBjZWxscwpmZW1hbGVfY2VsbHMgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRhdF9zZXggPT0gImZlbWFsZSIpLCBdCiMjIHRha2UgZm9yd2FyZCBvbmx5IHdpbGQtdHlwZQpmZW1hbGVfY2VsbHMgPC0gZmVtYWxlX2NlbGxzW3doaWNoKGZlbWFsZV9jZWxscyRleHBlcmltZW50ID09ICJtdXRhbnRzIiksIF0KIyMgZ2V0IGNlbGwgbmFtZXMKZmVtYWxlX2NlbGxzIDwtIHJvd25hbWVzKGZlbWFsZV9jZWxscykKIyMgc3Vic2V0IG91ciBjZWxsIGdyb3VwIGRmIHRvIGtlZXAgb25seSB0aGVzZSBjZWxscwojZmVtYWxlX2NlbGxfZ3JvdXBfZGYgPC0gZmVtYWxlX2NlbGxfZ3JvdXBfZGZbd2hpY2goZmVtYWxlX2NlbGxfZ3JvdXBfZGYkY2VsbF9pZCAlaW4lIGZlbWFsZV9jZWxscyksXQojIyBzdWJzZXQgU2V1cmF0IG9iamVjdCB0byBjb250YWluIGNlbGxzIG9mIGludGVyZXN0ICAKZmVtYWxlLnNldXJhdC5vYmplY3QgPC0gU3Vic2V0RGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgY2VsbHMgPSBmZW1hbGVfY2VsbHMpCiMjIG1ha2UgbmV3IGNvdW50cyBhbmQgcGhlbm86CmRhdGEgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YShmZW1hbGUuc2V1cmF0Lm9iamVjdCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikpLCAnc3BhcnNlTWF0cml4JykKcGQgPC0gZGF0YS5mcmFtZShmZW1hbGUuc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpCiMjIGtlZXAgb25seSB0aGUgY29sdW1ucyB0aGF0IGFyZSByZWxldmFudAojcERhdGEgPC0gcGQgJT4lIHNlbGVjdChvcmlnLmlkZW50LCBuQ291bnRfUk5BLCBuRmVhdHVyZV9STkEpCmZEYXRhIDwtIGRhdGEuZnJhbWUoZ2VuZV9zaG9ydF9uYW1lID0gcm93Lm5hbWVzKGRhdGEpLCByb3cubmFtZXMgPSByb3cubmFtZXMoZGF0YSkpCiMjIENvbnN0cnVjdCBtb25vY2xlIGNkcwpmZW1hbGUubW9ub2NsZS5vYmplY3QgPC0gbmV3X2NlbGxfZGF0YV9zZXQoZXhwcmVzc2lvbl9kYXRhID0gZGF0YSwgY2VsbF9tZXRhZGF0YSA9IHBkLCBnZW5lX21ldGFkYXRhID0gZkRhdGEpCiMjIHByZXByb2Nlc3MKZmVtYWxlLm1vbm9jbGUub2JqZWN0ID0gcHJlcHJvY2Vzc19jZHMoZmVtYWxlLm1vbm9jbGUub2JqZWN0LCBudW1fZGltID0gNTAsIG5vcm1fbWV0aG9kID0gIm5vbmUiKSAgCiMjIG1ha2UgYSBuZXcgZGF0YWZyYW1lIGZvciBjZWxsIGdyb3VwcyAtIGl0IGlzIGNydWNpYWwgdG8gcmVmYWN0b3Igb3RoZXJ3aXNlIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24gdGhpbmtzIGl0J3Mgb3V0IG9mIGJvdW5kcyAgCiNmZW1hbGVfY2VsbF9ncm91cF9kZiA8LSBkYXRhLmZyYW1lKGNlbGw9YXMuY2hhcmFjdGVyKGZhY3RvcihmZW1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkKSksIGNlbGxfZ3JvdXA9ZmFjdG9yKGZlbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2JpbikpICAKIyMgYWdncmVnYXRlIGV4cHJlc3Npb24KZmVtYWxlX2FnZ19tYXQgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihmZW1hbGUubW9ub2NsZS5vYmplY3QsIGdlbmVfbW9kdWxlX2RmX3NleCwgZXhjbHVkZS5uYSA9IEZBTFNFKQpgYGAKCm1hbGUKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMn0KIyBtYWxlX2FnZ19tYXQKIyMgcmVvcmRlciB1c2luZyBuZXcgb3JkZXIKbWFsZV9hZ2dfbWF0IDwtIG1hbGVfYWdnX21hdFtyb3cub3JkZXIsIF0KCiMjIG1ha2UgYW4gYW5vdGF0aW9uCmFubm9fbWFsZSA8LSBkYXRhLmZyYW1lKG1hbGUubW9ub2NsZS5vYmplY3RAY29sRGF0YSRhdF9zZXgsIG1hbGUubW9ub2NsZS5vYmplY3RAY29sRGF0YSRvbGRfcHRfdmFsdWVzLCBnZW5vdHlwZSA9IG1hbGUubW9ub2NsZS5vYmplY3RAY29sRGF0YSRpZGVudGl0eV91cGRhdGVkLCByb3cubmFtZXMgPSByb3duYW1lcyhtYWxlLm1vbm9jbGUub2JqZWN0QGNvbERhdGEpKQpuYW1lcyhhbm5vX21hbGUpIDwtIGMoInNleCIsICJQc2V1ZG90aW1lIiwgImdlbm90eXBlIikKCiMjIG1ha2UgYW5ub3RhdGlvbiBjb2xvdXJzCmFubm90YXRpb25fY29sb3VycyA8LSBsaXN0KHNleCA9IGMobWFsZT0iIzAxNmMwMCIsIGZlbWFsZT0iI2E1MmIxZSIsICdwcmUtZGV0JyA9ICIjMDA1MmM1IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFBzZXVkb3RpbWUgPSBtYWdtYSgxMiwgZGlyZWN0aW9uID0gMSkpCgojIyBjaGFuZ2UgdGhlIG9yZGVyIG9mIHRoZSBkYXRhIGZyYW1lCmNvbC5vcmRlci5tYWxlIDwtIHJvd25hbWVzKGFubm9fbWFsZVt3aXRoKGFubm9fbWFsZSwgb3JkZXIoZ2Vub3R5cGUsIFBzZXVkb3RpbWUpKSwgXSkKbWFsZV9hZ2dfbWF0IDwtIG1hbGVfYWdnX21hdFssY29sLm9yZGVyLm1hbGVdCgojIyBwbG90CmhlYXRtYXBfbWFsZSA8LSBwaGVhdG1hcDo6cGhlYXRtYXAobWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgICNzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBzaG93X2NvbG5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBsZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sID0gYW5ub19tYWxlLCAKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbl9jb2xvdXJzLCAKICAgICAgICAgICAgICAgICAgIGN1dHJlZV9yb3dzID0gMTIpCgpoZWF0bWFwX21hbGUKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDEyfQojIGZlbWFsZV9hZ2dfbWF0CiMjIHJlb3JkZXIgdXNpbmcgbmV3IG9yZGVyCmZlbWFsZV9hZ2dfbWF0IDwtIGZlbWFsZV9hZ2dfbWF0W3Jvdy5vcmRlciwgXQoKIyMgbWFrZSBhbiBhbm90YXRpb24KYW5ub19mZW1hbGUgPC0gZGF0YS5mcmFtZShmZW1hbGUubW9ub2NsZS5vYmplY3RAY29sRGF0YSRhdF9zZXgsIGZlbWFsZS5tb25vY2xlLm9iamVjdEBjb2xEYXRhJG9sZF9wdF92YWx1ZXMsIGdlbm90eXBlID0gZmVtYWxlLm1vbm9jbGUub2JqZWN0QGNvbERhdGEkaWRlbnRpdHlfdXBkYXRlZCwgcm93Lm5hbWVzID0gcm93bmFtZXMoZmVtYWxlLm1vbm9jbGUub2JqZWN0QGNvbERhdGEpKQpuYW1lcyhhbm5vX2ZlbWFsZSkgPC0gYygic2V4IiwgIlBzZXVkb3RpbWUiLCAiZ2Vub3R5cGUiKQoKIyMgbWFrZSBhbm5vdGF0aW9uIGNvbG91cnMKYW5ub3RhdGlvbl9jb2xvdXJzIDwtIGxpc3Qoc2V4ID0gYyhtYWxlPSIjMDE2YzAwIiwgZmVtYWxlPSIjYTUyYjFlIiwgJ3ByZS1kZXQnID0gIiMwMDUyYzUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgUHNldWRvdGltZSA9IG1hZ21hKDEyLCBkaXJlY3Rpb24gPSAxKSkKCiMjIGNoYW5nZSB0aGUgb3JkZXIgb2YgdGhlIGRhdGEgZnJhbWUKY29sLm9yZGVyLmZlbWFsZSA8LSByb3duYW1lcyhhbm5vX2ZlbWFsZVt3aXRoKGFubm9fZmVtYWxlLCBvcmRlcihnZW5vdHlwZSwgUHNldWRvdGltZSkpLCBdKQpmZW1hbGVfYWdnX21hdCA8LSBmZW1hbGVfYWdnX21hdFssY29sLm9yZGVyLmZlbWFsZV0KCiMjIHBsb3QKaGVhdG1hcF9mZW1hbGUgPC0gcGhlYXRtYXA6OnBoZWF0bWFwKGZlbWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgICNzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBzaG93X2NvbG5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBsZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm9fZmVtYWxlLCAKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbl9jb2xvdXJzLCAKICAgICAgICAgICAgICAgICAgIGN1dHJlZV9yb3dzID0gMTIpCgpoZWF0bWFwX2ZlbWFsZQoKIyMgc2F2ZSBhIHBoZWF0bWFwOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80MzA1MTUyNS9ob3ctdG8tZHJhdy1waGVhdG1hcC1wbG90LXRvLXNjcmVlbi1hbmQtYWxzby1zYXZlLXRvLWZpbGUKYGBgCgpzaWRlIHBsb3RzIHdpdGggZ3JvdXBzIG9mIG11dGFudCBjZWxscwoKZmVtYWxlCmBgYHtyfQojIyBtYWtlIGEgbmV3IGdyb3VwaW5nIGZvciBjZWxscyBiYXNlZCBvbiB0aGVpciBpZGVudGl0eQptdXRhbnRfZ3JvdXBfZmVtYWxlIDwtIGRhdGEuZnJhbWUoY2VsbCA9IHJvd25hbWVzKGZlbWFsZS5tb25vY2xlLm9iamVjdEBjb2xEYXRhKSwgY2VsbF9ncm91cCA9IGZlbWFsZS5tb25vY2xlLm9iamVjdEBjb2xEYXRhJGlkZW50aXR5X3VwZGF0ZWQpCgojIyBhZ2dyZWdhdGUgZXhwcmVzc2lvbgpmZW1hbGVfYWdnX21hdF9ncm91cGVkIDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24oZmVtYWxlLm1vbm9jbGUub2JqZWN0LCBnZW5lX21vZHVsZV9kZl9zZXgsIG11dGFudF9ncm91cF9mZW1hbGUsIGV4Y2x1ZGUubmEgPSBGQUxTRSkKCiMjIHJlb3JkZXIgdXNpbmcgbmV3IG9yZGVyCmZlbWFsZV9hZ2dfbWF0X2dyb3VwZWQgPC0gZmVtYWxlX2FnZ19tYXRfZ3JvdXBlZFtyb3cub3JkZXIsIF0KCiMjIHBsb3QKcGhlYXRtYXA6OnBoZWF0bWFwKGZlbWFsZV9hZ2dfbWF0X2dyb3VwZWQsIAogICAgICAgICAgICAgICAgICAgI3NjYWxlPSJyb3ciLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLAogICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICBsZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAjYW5ub3RhdGlvbl9jb2wgPSBhbm5vX2ZlbWFsZSwgCiAgICAgICAgICAgICAgICAgICAjYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uX2NvbG91cnMsIAogICAgICAgICAgICAgICAgICAgY3V0cmVlX3Jvd3MgPSAxMikKCgpgYGAKCm1hbGUKYGBge3J9CgpgYGAKCm1vZHVsZSAxMiBpbnNwZWN0aW9uCgpgYGB7ciwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMn0KIyMgbWFrZSBhIGRmIGZvciBtb2R1bGUgMTIgZ2VuZXMKbW9kdWxlLjEyLmdlbmVzIDwtIGdlbmVfbW9kdWxlX2RmX3NleFtnZW5lX21vZHVsZV9kZl9zZXgkbW9kdWxlID09IDEyLCBdJGlkCm1vZHVsZS4xMi5nZW5lcyA8LSBkYXRhLmZyYW1lKGlkID0gbW9kdWxlLjEyLmdlbmVzLCBncm91cCA9IG1vZHVsZS4xMi5nZW5lcykKCiMjIHByZXBhcmUgY3VzdG9tIGRhdGFmcmFtZSBmb3IgYWxsIGNlbGxzIGJ5IG1vZHVsZXM6CmFnZ19tYXRfbW9kdWxlXzEyIDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24obW9ub2NsZS5vYmplY3QsIG1vZHVsZS4xMi5nZW5lcykKCiMjIG1ha2UgYW4gYW5vdGF0aW9uCmFubm9fbm9fZ3JvdXAgPC0gZGF0YS5mcmFtZShtb25vY2xlLm9iamVjdEBjb2xEYXRhJHNleF9VTUFQLCBtb25vY2xlLm9iamVjdEBjb2xEYXRhJG9sZF9wdF92YWx1ZXMsIHJvdy5uYW1lcyA9IHJvd25hbWVzKG1vbm9jbGUub2JqZWN0QGNvbERhdGEpKQpuYW1lcyhhbm5vX25vX2dyb3VwKSA8LSBjKCJzZXgiLCAiUHNldWRvdGltZSIpCgojIyBtYWtlIGFubm90YXRpb24gY29sb3Vycwphbm5vdGF0aW9uX2NvbG91cnMgPC0gbGlzdChzZXggPSBjKG1hbGU9IiMwMTZjMDAiLCBmZW1hbGU9IiNhNTJiMWUiLCAncHJlLWRldCcgPSAiIzAwNTJjNSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBQc2V1ZG90aW1lID0gbWFnbWEoMTIsIGRpcmVjdGlvbiA9IDEpKQoKIyMgY2hhbmdlIHRoZSBvcmRlciBvZiB0aGUgZGF0YSBmcmFtZQpjb2wub3JkZXIgPC0gYyhwcmVfZGV0X29yZGVyZWRfY2VsbHMsIGZlbWFsZV9vcmRlcmVkX2NlbGxzLCBtYWxlX29yZGVyZWRfY2VsbHMpCmFnZ19tYXRfbW9kdWxlXzEyIDwtIGFnZ19tYXRfbW9kdWxlXzEyWyxjb2wub3JkZXJdCgojIyBwbG90CnBoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X21vZHVsZV8xMiwgCiAgICAgICAgICAgICAgICAgICAjc2NhbGU9InJvdyIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIHNob3dfY29sbmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sID0gYW5ub19ub19ncm91cCwgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycywKICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDcsCiAgICAgICAgICAgICAgICAgICBjdXRyZWVfcm93cyA9IDEyKQpgYGAKc2F2ZSBwbG90CmBgYHtyfQpoZWF0bWFwX21vZHVsZV8xMiA8LSBwaGVhdG1hcDo6cGhlYXRtYXAoYWdnX21hdF9tb2R1bGVfMTIsIAogICAgICAgICAgICAgICAgICAgI3NjYWxlPSJyb3ciLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBzaG93X2NvbG5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm9fbm9fZ3JvdXAsIAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uX2NvbG91cnMsCiAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSA3LAogICAgICAgICAgICAgICAgICAgY3V0cmVlX3Jvd3MgPSAxMikKCgoKCmBgYAoKQVAyIEV4cHJlc3Npb24KCmBgYHtyfQojIyByZWFkaW5nIHRhYmxlIG9mIEFQMiBnZW5lcwphcDJfZ2VuZXNfdGFibGUgPC0gcmVhZC5kZWxpbShmaWxlID0gIn4vZGF0YS9BUDJfZ2VuZXNfdGFibGUudHh0IiwgaGVhZGVyID0gVFJVRSwgc2VwID0iXHQiKQoKIyMgZXh0cmFjdCBsaXN0IG9mIGdlbmVzCmFwMl9nZW5lc19saXN0IDwtIGRwbHlyOjpwdWxsKGFwMl9nZW5lc190YWJsZSwgR2VuZS5JRCkKYXAyX2dlbmVzX2xpc3QgPC0gZ3N1YigiXyIsICItIiwgYXAyX2dlbmVzX2xpc3QpCgojIyBtYWtlIGEgZGYgZm9yIGdlbmVzCmFwMl9nZW5lc19saXN0IDwtIGRhdGEuZnJhbWUoaWQgPSBhcDJfZ2VuZXNfbGlzdCwgZ3JvdXAgPSBhcDJfZ2VuZXNfbGlzdCkKCiMjIHByZXBhcmUgY3VzdG9tIGRhdGFmcmFtZSBmb3IgYWxsIGNlbGxzIGJ5IG1vZHVsZXM6CmFnZ19tYXRfYXAycyA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1vbm9jbGUub2JqZWN0LCBhcDJfZ2VuZXNfbGlzdCkKCiMjIGNoYW5nZSB0aGUgb3JkZXIgb2YgdGhlIGRhdGEgZnJhbWUKY29sLm9yZGVyIDwtIGMocHJlX2RldF9vcmRlcmVkX2NlbGxzLCBmZW1hbGVfb3JkZXJlZF9jZWxscywgbWFsZV9vcmRlcmVkX2NlbGxzKQphZ2dfbWF0X2FwMnMgPC0gYWdnX21hdF9hcDJzWyxjb2wub3JkZXJdCgojIyBwbG90CnBoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X2FwMnMsIAogICAgICAgICAgICAgICAgICAgI3NjYWxlPSJyb3ciLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZD0iY29tcGxldGUiLAogICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBhbm5vX25vX2dyb3VwLCAKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbl9jb2xvdXJzLAogICAgICAgICAgICAgICAgICAgZm9udHNpemVfcm93ID0gNywKICAgICAgICAgICAgICAgICAgIGN1dHJlZV9yb3dzID0gMykKYGBgCgoKIyMjIE1vZHVsZSBBbmFseXNpcyAKClJlYWQgaW4gS2FzaWEncyBtb2R1bGVzOgpgYGB7cn0KIyMgcmVhZCBpbiBrYXNpYSBtb2R1bGVzOgprYXNpYV9jbHVzdGVycyA8LSByZWFkLmNzdihmaWxlID0gIn4vZGF0YS9Nb2R1bGVzX0NsdXN0ZXJzX1BoZW5vdHlwZXMuY3N2IiwgaGVhZGVyID0gVFJVRSkKCiMjIGNoYW5nZSBfIHRvIC06Cmthc2lhX2NsdXN0ZXJzJG5ldy5nZW5lLklEIDwtIGdzdWIoIl8iLCAiLSIsIGthc2lhX2NsdXN0ZXJzJG5ldy5nZW5lLklEKQoKIyMgZmlsdGVyIG91dCBnZW5lcyBub3QgaW4gbW9kdWxlcyBnZW5lX21vZHVsZV9kZl9zZXg6Cmthc2lhX2NsdXN0ZXJzX2ZpbHRlcmVkIDwtIGthc2lhX2NsdXN0ZXJzW3doaWNoKGthc2lhX2NsdXN0ZXJzJG5ldy5nZW5lLklEICVpbiUgZ2VuZV9tb2R1bGVfZGZfc2V4JGlkKSwgXQoKIyMgcmVuYW1lIG5ldyBnZW5lIGlkCm5hbWVzKGthc2lhX2NsdXN0ZXJzX2ZpbHRlcmVkKVsyXSA8LSAiaWQiCgojIyBtZXJnZSB0b2dldGhlcgptb2R1bGVzX21lcmdlZF9kZiA8LSBtZXJnZShrYXNpYV9jbHVzdGVyc19maWx0ZXJlZCwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBieSA9ICJpZCIpCgojIyBsb29rIGF0IHRoZSBlbnJpY2htZW50IHdpdGggYSBkb3RwbG90Ogpkb3RfcGxvdF9kZl9wYyA8LSAoYXMuZGF0YS5mcmFtZS5tYXRyaXgocHJvcC50YWJsZSh0YWJsZShtb2R1bGVzX21lcmdlZF9kZiRLYXNpYS5DbHVzdGVyLCBkZl9tZXRhX2RhdGEkaWRlbnRpdHlfY29tYmluZWQpLCBtYXJnaW4gPSAyKSkgKiAxMDApCmBgYAoKCgoKCgoKCgpOT1QgVVNFRApjb21wbGV4IGhlYXRtYXAgdmVyc2lvbgoKYGBge3J9CiMjIG1ha2UgaW50byBtYXRyaXggdG8gcGxvdApjb2wub3JkZXIgPC0gYWdnX21hdF9hbGxfY2VsbHNfbWF0cml4IDwtIGFzLm1hdHJpeChhZ2dfbWF0X2FsbF9jZWxscykKYGBgCgptYWtlIGFubm90YXRpb24KYGBge3J9CiMjIGV4dHJhY3QgcHNldWRvdGltZSB2YWx1ZXM6CnB0X3ZhbHVlcyA8LSBhcy5kYXRhLmZyYW1lKHBzZXVkb3RpbWUobW9ub2NsZS5vYmplY3QsIHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIpKQpuYW1lcyhwdF92YWx1ZXMpIDwtICJtb25vY2xlX3B0X3NleF93dCIKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXggPC0gQWRkTWV0YURhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHB0X3ZhbHVlcykKCiMjIHNhdmUgcHQgdmFsdWVzCndyaXRlLmNzdihwdF92YWx1ZXMsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC9wdF92YWx1ZXNfc2V4X29ubHkuY3N2IikKYGBgCgpgYGB7cn0KbGlicmFyeShjaXJjbGl6ZSkKIyMgbWFrZSB0aGUgYW5ub3RhdGlvbiBkZgojIyBnZXQgbWV0YSBkYXRhIGZyb20gc2V1cmF0IG9iamVjdCBhbmQgdGhlbiBzdWJzZXQgcm93cyBvdXQgdGhhdCBhcmUgd3QKZGZfYW5ubyA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2gocm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhKSAlaW4lIGNvbG5hbWVzKGFnZ19tYXRfYWxsX2NlbGxzX21hdHJpeCkpLCBdCiMjIGdldCBvbmx5IGNvbHVtbnMgb2YgaW50ZXJlc3Q6CmRmX2Fubm8gPC0gZGZfYW5ub1sgLGMoInNleCIsICJtb25vY2xlX3B0X3NleF93dCIpLCBkcm9wID0gRkFMU0UgXQoKIyMgb3JkZXIgYW5ub3RhdGlvbgpkZl9hbm5vIDwtIGRmX2Fubm9bd2l0aChkZl9hbm5vLCBvcmRlcihzZXgsIG1vbm9jbGVfcHRfc2V4X3d0KSksXQoKIyMgb3JkZXIgY29scyBpbiB0aGUgbWF0cml4CmFnZ19tYXRfYWxsX2NlbGxzX21hdHJpeCA8LSBhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXhbICxtYXRjaChjb2xuYW1lcyhhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXgpLCByb3duYW1lcyhkZl9hbm5vKSldCgojIyBtYWtlIGFubm90YXRpb24KaGVhdG1hcF9hbm5vdGF0aW9uIDwtIEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gY2x1c3Rlcl9hbm5vLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3Qoc2V4ID0gYyhtYWxlPSIjMDE2YzAwIiwgZmVtYWxlPSIjYTUyYjFlIiwgYHByZS1kZXRgID0gIiMwMDUyYzUiKSwgbW9ub2NsZV9wdF9zZXhfd3QgPSBjb2xvclJhbXAyKGMoMTo3MCksIGluZmVybm8oNzApKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCmhlYXRtYXBfYW5ub3RhdGlvbiA8LSBIZWF0bWFwQW5ub3RhdGlvbihzZXggPSBkZl9hbm5vJHNleCwgcHQgPSBkZl9hbm5vJG1vbm9jbGVfcHRfc2V4X3d0KQpgYGAKCnBsb3QKYGBge3J9CiMjIG1ha2UgaGVhdG1hcAptb2R1bGVzX2hlYXRtYXAgPC0gSGVhdG1hcChhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXgsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsCiAgICAgICAgY29sdW1uX2xhYmVscyA9IHJlcCgiIiwgbmNvbChhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXgpKSwKICAgICAgICAjcm93X29yZGVyID0gbW9kdWxlX2RlbmRybyRvcmRlciwKICAgICAgICBjbHVzdGVyaW5nX21ldGhvZF9jb2x1bW5zID0gIndhcmQuRDIiLAogICAgICAgIGJvdHRvbV9hbm5vdGF0aW9uID0gaGVhdG1hcF9hbm5vdGF0aW9uLAogICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPQogICJSZFlsQnUiKSkpKDEwMCksIAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpKQoKIyMgcHJpbnQKZHJhdyhtb2R1bGVzX2hlYXRtYXAsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmBgYAoKYGBge3J9CiMjIGV4dHJhY3QgY291bnRzIGZyb20gMTB4IG9iamVjdAptYXRyaXhfdGVueF9jb3VudHMgPC0gYXMubWF0cml4KEdldEFzc2F5RGF0YShwYl9zZXhfZmlsdGVyZWQsIGFzc2F5ID0gIlJOQSIpKQojbmsucmF3LmRhdGEgPC0gYXMubWF0cml4KEdldEFzc2F5RGF0YShwYl9zZXhfZmlsdGVyZWQsIHNsb3QgPSAiY291bnRzIilbLCBXaGljaENlbGxzKHBibWMsIGlkZW50ID0gIk5LIildKQoKIyMgY2hlY2sgaXQgaXMgdGhlIHNhbWUgYXMgdGhlIG1lcmdlZCBvYmplY3QgUk5BIHNsb3QKCiMjIGNoZWNrIGl0IGlzIHRoZSBzYW1lIGFzIHRoZSBtb25vY2xlIG9iamVjdAptYXRyaXhfdGVueF9jb3VudHNfbW9ub2NsZSA8LSBhcy5tYXRyaXgoYXMuZGF0YS5mcmFtZSgobW9ub2NsZS5vYmplY3RAYXNzYXlzKSkpCmBgYAoKYGBge3J9CiMjIG1ha2UgaGVhdG1hcAptb2R1bGVzX2hlYXRtYXAgPC0gSGVhdG1hcChtYXRyaXhfdGVueF9jb3VudHMsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fbGFiZWxzID0gcmVwKCIiLCBuY29sKG1hdHJpeF90ZW54X2NvdW50cykpLAogICAgICAgICNyb3dfb3JkZXIgPSBtb2R1bGVfZGVuZHJvJG9yZGVyLAogICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kX2NvbHVtbnMgPSAid2FyZC5EMiIsCiAgICAgICAgI2JvdHRvbV9hbm5vdGF0aW9uID0gaGVhdG1hcF9hbm5vdGF0aW9uLAogICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPQogICJSZFlsQnUiKSkpKDEwMCksIAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpKQoKIyMgcHJpbnQKZHJhdyhtb2R1bGVzX2hlYXRtYXAsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmBgYAoKIyMjIyBwbG90IGFzIGEgZnVuY3Rpb24gb2YgcHNldWRvdGltZQoKTm93LCB3ZSB3aWxsIGludGVncmF0ZSB0aGUgYnJhbmNoIGRhdGEgd2UgcHJvZHVjZWQgdXNpbmcgc2xpbmdzaG90IGFuZCB0aGUgcHNldWRvdGltZSB2YWx1ZXMgdG8gcGxvdCB0aGlzIGhlYXRtYXAuIAoKTW9ub2NsZTMgaGFzIGEgaGFuZHkgZnVuY3Rpb24gdGhhdCBhbGxvd3MgdXMgdG8gYWdncmVnYXRlIGV4cHJlc3Npb24gb2YgZ3JvdXBzIG9mIGNlbGxzIGNhbGxlZCBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uLiAKClRoZSBjb2RlIGZvciB0aGlzIGlzIGxvY2F0ZWQgaGVyZTogaHR0cHM6Ly9naXRodWIuY29tL2NvbGUtdHJhcG5lbGwtbGFiL21vbm9jbGUzL2Jsb2IvMWEwMjI3NDIwOWM3NjVmZTdhNjBmNTMzYTMxYjFkYTNkYWNmNjc4NS9SL2NsdXN0ZXJfZ2VuZXMuUiAKCkRlZmluZSB0aGUgZ3JvdXBzIG9mIGNlbGxzCmBgYHtyfQojIyBTcGxpdCBjZWxscyBpbnRvIGdyb3VwcyBvZiBzZXhlcwpmZW1hbGVfY2VsbHMgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gImZlbWFsZSIpLCBdCm1hbGVfY2VsbHMgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gIm1hbGUiKSwgXQpwcmVfZGV0X2NlbGxzIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJwcmUtZGV0IiksIF0KCiMjIGluc3BlY3QgcmFuZ2Ugb2YgcHQgdmFsdWVzIHRvIGRldGVybWluZSBiaW4gd2lkdGgKaGlzdChmZW1hbGVfY2VsbHMkUFRfTGluZWFnZUZlbWFsZSkKaGlzdChtYWxlX2NlbGxzJFBUX0xpbmVhZ2VNYWxlKQpoaXN0KHByZV9kZXRfY2VsbHMkUFRfTGluZWFnZUZlbWFsZSkKaGlzdChwcmVfZGV0X2NlbGxzJFBUX0xpbmVhZ2VNYWxlKQoKYGBgCgpVc2UgYSBiaW4gd2lkdGggb2YgMgoKdGhlcmUgd2lsbCBiZSB0d28gb2JqZWN0cyBmb3IgdGhlIGNlbGxfZ3JvdXBfZGY6IG1hbGUgYnJhbmNoIGFuZCBmZW1hbGUgYnJhbmNoLiBCb3RoIHdpbGwgaW5jbHVkZSB0aGUgcHJlLWRldCBicmFuY2gKCmBgYHtyfQojIyBEZWZpbmUgbWFsZSBhbmQgZmVtYWxlIGJyYW5jaCBjZWxscwojIG1hbGUKbWFsZV9icmFuY2hfbWV0YV9kYXRhIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJwcmUtZGV0IiB8IHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gIm1hbGUiKSwgXQoKbWFsZV9icmFuY2hfbWV0YV9kYXRhIDwtIGRhdGEuZnJhbWUoY2VsbF9pZCA9IHJvd25hbWVzKG1hbGVfYnJhbmNoX21ldGFfZGF0YSksIHB0ID0gbWFsZV9icmFuY2hfbWV0YV9kYXRhJFBUX0xpbmVhZ2VNYWxlKQoKbWFsZV9jZWxsX2dyb3VwX2RmIDwtIG1hbGVfYnJhbmNoX21ldGFfZGF0YQoKI2ZlbWFsZQpmZW1hbGVfYnJhbmNoX21ldGFfZGF0YSA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAicHJlLWRldCIgfCB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJmZW1hbGUiKSwgXQoKZmVtYWxlX2JyYW5jaF9tZXRhX2RhdGEgPC0gZGF0YS5mcmFtZShjZWxsX2lkID0gcm93bmFtZXMoZmVtYWxlX2JyYW5jaF9tZXRhX2RhdGEpLCBwdCA9IGZlbWFsZV9icmFuY2hfbWV0YV9kYXRhJFBUX0xpbmVhZ2VGZW1hbGUpCgpmZW1hbGVfY2VsbF9ncm91cF9kZiA8LSBmZW1hbGVfYnJhbmNoX21ldGFfZGF0YQoKIyMgd2hhdCdzIHRoZSByYW5nZSBvZiB2YWx1ZXMgZm9yIGVhY2ggcHQ/CgpyYW5nZShmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCkKcmFuZ2UobWFsZV9jZWxsX2dyb3VwX2RmJHB0KQpgYGAKCmBgYHtyfQojIyBtYWtlIGJpbiB3aWR0aHMKIyBtYWtlIGEgbmV3IGNvbCBmb3IgYW5ub3RhdGlvbgpmZW1hbGVfY2VsbF9ncm91cF9kZiRwdF9iaW4gPC0gTkEKZm9yKGkgaW4gc2VxKDIsNjgsMikpewogIGZlbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2Jpblt3aGljaChmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCA8IGkgJiBmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCA+PSAoaS0yKSldIDwtIGkKfQoKbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2JpbiA8LSBOQQpmb3IoaSBpbiBzZXEoMiw2OCwyKSl7CiAgbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2Jpblt3aGljaChtYWxlX2NlbGxfZ3JvdXBfZGYkcHQgPCBpICYgbWFsZV9jZWxsX2dyb3VwX2RmJHB0ID49IChpLTIpKV0gPC0gaQp9CiMgdGhlbiByZW1vdmUgb2xkIHB0IHZhbHVlcwptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gbWFsZV9jZWxsX2dyb3VwX2RmWyAsLTJdCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGZlbWFsZV9jZWxsX2dyb3VwX2RmWyAsLTJdCmBgYAoKYGBge3J9CiMjIFRoZSBvcmlnaW5hbCBvYmplY3QgY29udGFpbnMgYWxsIGNlbGxzLCB3ZSBqdXN0IHdhbnQgd2lsZC10eXBlIHNvIGxldCdzIHN1YnNldCBvdXQgZ2VuZV9tb2R1bGVfZGYgYW5kIGNlbGxfZ3JvdXBfZGYgYWNjb3JkaW5nbHkKCiMjIG1hbGUKIyMgc3Vic2V0IG91dCBvbmx5IG1hbGUgYW5kIHByZSBkZXRlcm1pbmF0aW9uIGNlbGxzCm1hbGVfY2VsbHMgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gIm1hbGUiIHwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAicHJlLWRldCIpLCBdCiMjIHRha2UgZm9yd2FyZCBvbmx5IHdpbGQtdHlwZQptYWxlX2NlbGxzIDwtIG1hbGVfY2VsbHNbd2hpY2gobWFsZV9jZWxscyRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1QiIHwgbWFsZV9jZWxscyRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1RfMTBYIiksIF0KI21hbGVfY2VsbHMgPC0gbWFsZV9jZWxsc1t3aGljaChtYWxlX2NlbGxzJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVF8xMFgiKSwgXQojIyBnZXQgY2VsbCBuYW1lcwptYWxlX2NlbGxzIDwtIHJvd25hbWVzKG1hbGVfY2VsbHMpCiMjIHN1YnNldCBvdXIgY2VsbCBncm91cCBkZiB0byBrZWVwIG9ubHkgdGhlc2UgY2VsbHMKbWFsZV9jZWxsX2dyb3VwX2RmIDwtIG1hbGVfY2VsbF9ncm91cF9kZlt3aGljaChtYWxlX2NlbGxfZ3JvdXBfZGYkY2VsbF9pZCAlaW4lIG1hbGVfY2VsbHMpLF0KIyMgc3Vic2V0IFNldXJhdCBvYmplY3QgdG8gY29udGFpbiBjZWxscyBvZiBpbnRlcmVzdCAgCm1hbGUuc2V1cmF0Lm9iamVjdCA8LSBTdWJzZXREYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBjZWxscyA9IG1hbGVfY2VsbHMpCiMjIG1ha2UgbmV3IGNvdW50cyBhbmQgcGhlbm86CmRhdGEgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YShtYWxlLnNldXJhdC5vYmplY3QsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCnBkIDwtIGRhdGEuZnJhbWUobWFsZS5zZXVyYXQub2JqZWN0QG1ldGEuZGF0YSkKIyMga2VlcCBvbmx5IHRoZSBjb2x1bW5zIHRoYXQgYXJlIHJlbGV2YW50CiNwRGF0YSA8LSBwZCAlPiUgc2VsZWN0KG9yaWcuaWRlbnQsIG5Db3VudF9STkEsIG5GZWF0dXJlX1JOQSkKZkRhdGEgPC0gZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSByb3cubmFtZXMoZGF0YSksIHJvdy5uYW1lcyA9IHJvdy5uYW1lcyhkYXRhKSkKIyMgQ29uc3RydWN0IG1vbm9jbGUgY2RzCm1hbGUubW9ub2NsZS5vYmplY3QgPC0gbmV3X2NlbGxfZGF0YV9zZXQoZXhwcmVzc2lvbl9kYXRhID0gZGF0YSwgY2VsbF9tZXRhZGF0YSA9IHBkLCBnZW5lX21ldGFkYXRhID0gZkRhdGEpCiMjIHByZXByb2Nlc3MKbWFsZS5tb25vY2xlLm9iamVjdCA9IHByZXByb2Nlc3NfY2RzKG1hbGUubW9ub2NsZS5vYmplY3QsIG51bV9kaW0gPSA1MCwgbm9ybV9tZXRob2QgPSAibm9uZSIpICAKIyMgbWFrZSBhIG5ldyBkYXRhZnJhbWUgZm9yIGNlbGwgZ3JvdXBzIC0gaXQgaXMgY3J1Y2lhbCB0byByZWZhY3RvciBvdGhlcndpc2UgYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbiB0aGlua3MgaXQncyBvdXQgb2YgYm91bmRzICAKbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGRhdGEuZnJhbWUoY2VsbD1hcy5jaGFyYWN0ZXIoZmFjdG9yKG1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkKSksIGNlbGxfZ3JvdXA9ZmFjdG9yKG1hbGVfY2VsbF9ncm91cF9kZiRwdF9iaW4pKSAgCiMjIGFnZ3JlZ2F0ZSBleHByZXNzaW9uCm1hbGVfYWdnX21hdCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1hbGUubW9ub2NsZS5vYmplY3QsIGdlbmVfbW9kdWxlX2RmX3NleCwgbWFsZV9jZWxsX2dyb3VwX2RmLCBleGNsdWRlLm5hID0gRkFMU0UpCgojIyBmZW1hbGUKIyMgc3Vic2V0IG91dCBvbmx5IG1hbGUgYW5kIHByZSBkZXRlcm1pbmF0aW9uIGNlbGxzCmZlbWFsZV9jZWxscyA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAiZmVtYWxlIiB8IHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gInByZS1kZXQiKSwgXQojIyB0YWtlIGZvcndhcmQgb25seSB3aWxkLXR5cGUKZmVtYWxlX2NlbGxzIDwtIGZlbWFsZV9jZWxsc1t3aGljaChmZW1hbGVfY2VsbHMkaWRlbnRpdHlfY29tYmluZWQgPT0gIldUIiB8IGZlbWFsZV9jZWxscyRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1RfMTBYIiksIF0KI2ZlbWFsZV9jZWxscyA8LSBmZW1hbGVfY2VsbHNbd2hpY2goZmVtYWxlX2NlbGxzJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVF8xMFgiKSwgXQojIyBnZXQgY2VsbCBuYW1lcwpmZW1hbGVfY2VsbHMgPC0gcm93bmFtZXMoZmVtYWxlX2NlbGxzKQojIyBzdWJzZXQgb3VyIGNlbGwgZ3JvdXAgZGYgdG8ga2VlcCBvbmx5IHRoZXNlIGNlbGxzCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGZlbWFsZV9jZWxsX2dyb3VwX2RmW3doaWNoKGZlbWFsZV9jZWxsX2dyb3VwX2RmJGNlbGxfaWQgJWluJSBmZW1hbGVfY2VsbHMpLF0KIyMgc3Vic2V0IFNldXJhdCBvYmplY3QgdG8gY29udGFpbiBjZWxscyBvZiBpbnRlcmVzdCAgCmZlbWFsZS5zZXVyYXQub2JqZWN0IDwtIFN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gZmVtYWxlX2NlbGxzKQojIyBtYWtlIG5ldyBjb3VudHMgYW5kIHBoZW5vOgpkYXRhIDwtIGFzKGFzLm1hdHJpeChHZXRBc3NheURhdGEoZmVtYWxlLnNldXJhdC5vYmplY3QsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCnBkIDwtIGRhdGEuZnJhbWUoZmVtYWxlLnNldXJhdC5vYmplY3RAbWV0YS5kYXRhKQojIyBrZWVwIG9ubHkgdGhlIGNvbHVtbnMgdGhhdCBhcmUgcmVsZXZhbnQKI3BEYXRhIDwtIHBkICU+JSBzZWxlY3Qob3JpZy5pZGVudCwgbkNvdW50X1JOQSwgbkZlYXR1cmVfUk5BKQpmRGF0YSA8LSBkYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IHJvdy5uYW1lcyhkYXRhKSwgcm93Lm5hbWVzID0gcm93Lm5hbWVzKGRhdGEpKQojIyBDb25zdHJ1Y3QgbW9ub2NsZSBjZHMKZmVtYWxlLm1vbm9jbGUub2JqZWN0IDwtIG5ld19jZWxsX2RhdGFfc2V0KGV4cHJlc3Npb25fZGF0YSA9IGRhdGEsIGNlbGxfbWV0YWRhdGEgPSBwZCwgZ2VuZV9tZXRhZGF0YSA9IGZEYXRhKQojIyBwcmVwcm9jZXNzCmZlbWFsZS5tb25vY2xlLm9iamVjdCA9IHByZXByb2Nlc3NfY2RzKGZlbWFsZS5tb25vY2xlLm9iamVjdCwgbnVtX2RpbSA9IDUwLCBub3JtX21ldGhvZCA9ICJub25lIikgIAojIyBtYWtlIGEgbmV3IGRhdGFmcmFtZSBmb3IgY2VsbCBncm91cHMgLSBpdCBpcyBjcnVjaWFsIHRvIHJlZmFjdG9yIG90aGVyd2lzZSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uIHRoaW5rcyBpdCdzIG91dCBvZiBib3VuZHMgIApmZW1hbGVfY2VsbF9ncm91cF9kZiA8LSBkYXRhLmZyYW1lKGNlbGw9YXMuY2hhcmFjdGVyKGZhY3RvcihmZW1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkKSksIGNlbGxfZ3JvdXA9ZmFjdG9yKGZlbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2JpbikpICAKIyMgYWdncmVnYXRlIGV4cHJlc3Npb24KZmVtYWxlX2FnZ19tYXQgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihmZW1hbGUubW9ub2NsZS5vYmplY3QsIGdlbmVfbW9kdWxlX2RmX3NleCwgZmVtYWxlX2NlbGxfZ3JvdXBfZGYsIGV4Y2x1ZGUubmEgPSBGQUxTRSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDV9CiMjIHVzZSB0aGVzZSBjbHVzdGVycyB0byByZW9yZGVyIHRoZSBtb2R1bGVzCm1hbGVfYWdnX21hdCA8LSBtYWxlX2FnZ19tYXRbbWF0Y2gobGV2ZWxzKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUpLCByb3cubmFtZXMobWFsZV9hZ2dfbWF0KSksIF0KZmVtYWxlX2FnZ19tYXQgPC0gZmVtYWxlX2FnZ19tYXRbbWF0Y2gobGV2ZWxzKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUpLCByb3cubmFtZXMoZmVtYWxlX2FnZ19tYXQpKSwgXQoKcGhlYXRtYXA6OnBoZWF0bWFwKG1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFKQoKcGhlYXRtYXA6OnBoZWF0bWFwKG1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0iY29sdW1uIiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFKQoKcGhlYXRtYXA6OnBoZWF0bWFwKG1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0ibm9uZSIsCiAgICAgICAgICAgICAgICAgICAjY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSkKCnBoZWF0bWFwOjpwaGVhdG1hcChmZW1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFKQoKcGhlYXRtYXA6OnBoZWF0bWFwKGZlbWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJjb2x1bW4iLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UpCgpwaGVhdG1hcDo6cGhlYXRtYXAoZmVtYWxlX2FnZ19tYXQsIAogICAgICAgICAgICAgICAgICAgc2NhbGU9Im5vbmUiLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UpCgpgYGAKCkNvbXBsZXhIZWF0bWFwIHZlcnNpb24KYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTJ9CiMjIHBoZWF0bWFwIGNhbGN1bGF0ZXMgWiBzY29yZXMgZm9yIHBsb3R0aW5nIHZhbHVlcwpzY2FsZV9tYXRyaXhfYnlfY29scyA8LSBmdW5jdGlvbiAoeCkgCnsKICAgIG0gPSBhcHBseSh4LCAxLCBtZWFuLCBuYS5ybSA9IFQpCiAgICBzID0gYXBwbHkoeCwgMSwgc2QsIG5hLnJtID0gVCkKICAgIHJldHVybigoeCAtIG0pL3MpCn0KCiMjIGNhbGN1bGF0ZSB6IHNjb3JlIGJ5IGNvbApmZW1hbGVfYWdnX21hdF9zY2FsZWQgPC0gdChhcy5tYXRyaXgoc2NhbGVfbWF0cml4X2J5X2NvbHModChmZW1hbGVfYWdnX21hdCkpKSkKbWFsZV9hZ2dfbWF0X3NjYWxlZCA8LSB0KGFzLm1hdHJpeChzY2FsZV9tYXRyaXhfYnlfY29scyh0KG1hbGVfYWdnX21hdCkpKSkKIyMgcmVvcmRlciBjb2xzCmZlbWFsZV9hZ2dfbWF0X3NjYWxlZCA8LSBmZW1hbGVfYWdnX21hdF9zY2FsZWRbbWF0Y2gobGV2ZWxzKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUpLCByb3cubmFtZXMoZmVtYWxlX2FnZ19tYXRfc2NhbGVkKSksIF0KbWFsZV9hZ2dfbWF0X3NjYWxlZCA8LSBtYWxlX2FnZ19tYXRfc2NhbGVkW21hdGNoKGxldmVscyhnZW5lX21vZHVsZV9kZl9zZXgkbW9kdWxlKSwgcm93Lm5hbWVzKG1hbGVfYWdnX21hdF9zY2FsZWQpKSwgXQoKIyMgcmVvcmRlciBiYXNlZCBvbiBjbHVzdGVycwpnZW5lc19wZXJfbW9kdWxlIDwtIGdlbmVzX3Blcl9tb2R1bGVbbWF0Y2gobGV2ZWxzKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUpLCByb3cubmFtZXMoZ2VuZXNfcGVyX21vZHVsZSkpLCBdCgojIyBjaGFuZ2UgbmFtZXMgZm9yIHJvdyBuYW1lcyB0byBpbmNsdWRlICJtb2R1bGUgIiBhdCB0aGUgYmVnaW5pbmcgb2YgdGhlbQpyb3cubmFtZXMoZmVtYWxlX2FnZ19tYXRfc2NhbGVkKSA8LSBzdHJpbmdyOjpzdHJfYygiTW9kdWxlICIsIHJvdy5uYW1lcyhmZW1hbGVfYWdnX21hdF9zY2FsZWQpKQpyb3cubmFtZXMobWFsZV9hZ2dfbWF0X3NjYWxlZCkgPC0gc3RyaW5ncjo6c3RyX2MoIk1vZHVsZSAiLCByb3cubmFtZXMobWFsZV9hZ2dfbWF0X3NjYWxlZCkpCgojIyBhZGQgbnVtYmVyIG9mIGNlbGxzIHRvIHRoZSByb3duYW1lcyBmb3IgdGhlIG1vZHVsZQpmb3IoaSBpbiBzZXFfYWxvbmcoZ2VuZXNfcGVyX21vZHVsZSRGcmVxKSl7CiAgcm93Lm5hbWVzKGZlbWFsZV9hZ2dfbWF0X3NjYWxlZClbaV0gPC0gc3RyaW5ncjo6c3RyX2Mocm93Lm5hbWVzKGZlbWFsZV9hZ2dfbWF0X3NjYWxlZClbaV0sIiAobiA9ICIgLGdlbmVzX3Blcl9tb2R1bGUkRnJlcVtpXSwgIikiKQp9CmZvcihpIGluIHNlcV9hbG9uZyhnZW5lc19wZXJfbW9kdWxlJEZyZXEpKXsKICByb3cubmFtZXMobWFsZV9hZ2dfbWF0X3NjYWxlZClbaV0gPC0gc3RyaW5ncjo6c3RyX2Mocm93Lm5hbWVzKG1hbGVfYWdnX21hdF9zY2FsZWQpW2ldLCIgKG4gPSAiICxnZW5lc19wZXJfbW9kdWxlJEZyZXFbaV0sICIpIikKfQoKIyMgYWRkIGFubm90YXRpb246CiNoZWF0bWFwX2Fubm90YXRpb24gPC0gSGVhdG1hcEFubm90YXRpb24oZGYgPSBjbHVzdGVyX2Fubm8sCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3QoCiMgSWRlbnRpdHkgPSBjKE1hbGU9IiMwMTZjMDAiLCBGZW1hbGU9IiNhNTJiMWUiLCBBc2V4dWFsPSAiIzAwNTJjNSIsIENvbW1pdHRlZCA9ICIjZjJlYjIzIikpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QoTWVkaWFuX1BzZXVkb3RpbWVfb2ZfQ2x1c3RlciA9IGxpc3QoZGlyZWN0aW9uID0gImhvcml6b250YWwiKSwgSWRlbnRpdHkgPSBsaXN0KG5yb3cgPSAxKSkpCgpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbW9kdWxlc19oZWF0bWFwX2ZlbWFsZSA8LSBIZWF0bWFwKGZlbWFsZV9hZ2dfbWF0X3NjYWxlZCwKICAgICAgICBjb2x1bW5fb3JkZXIgPSBOVUxMLAogICAgICAgICNyb3dfb3JkZXIgPSByb3cubmFtZXMoZmVtYWxlX2FnZ19tYXRfc2NhbGVkKVttb2R1bGVfZGVuZHJvJG9yZGVyXSwKICAgICAgICAjY2x1c3RlcmluZ19tZXRob2Rfcm93cyA9ICJ3YXJkLkQyIiwKICAgICAgICAjYm90dG9tX2Fubm90YXRpb24gPSBoZWF0bWFwX2Fubm90YXRpb24sCiAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9CiAgIlJkWWxCdSIpKSkoMTAwKSwgCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikpCgptb2R1bGVzX2hlYXRtYXBfbWFsZSA8LSBIZWF0bWFwKG1hbGVfYWdnX21hdF9zY2FsZWQsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICAjcm93X29yZGVyID0gbW9kdWxlX2RlbmRybyRvcmRlciwKICAgICAgICAjY2x1c3RlcmluZ19tZXRob2Rfcm93cyA9ICJ3YXJkLkQyIiwKICAgICAgICAjYm90dG9tX2Fubm90YXRpb24gPSBoZWF0bWFwX2Fubm90YXRpb24sCiAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9CiAgIlJkWWxCdSIpKSkoMTAwKSwgCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikpCgpkcmF3KG1vZHVsZXNfaGVhdG1hcF9mZW1hbGUsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmRyYXcobW9kdWxlc19oZWF0bWFwX21hbGUsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCgojIyBodHRwczovL3d3dy5iaW9zdGFycy5vcmcvcC8zODA1NDQvIApgYGAKCjQgYmluIHdpZHRoIAoKYGBge3J9CiMjIERlZmluZSBtYWxlIGFuZCBmZW1hbGUgYnJhbmNoIGNlbGxzCiMgbWFsZQptYWxlX2JyYW5jaF9tZXRhX2RhdGEgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gInByZS1kZXQiIHwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAibWFsZSIpLCBdCgptYWxlX2JyYW5jaF9tZXRhX2RhdGEgPC0gZGF0YS5mcmFtZShjZWxsX2lkID0gcm93bmFtZXMobWFsZV9icmFuY2hfbWV0YV9kYXRhKSwgcHQgPSBtYWxlX2JyYW5jaF9tZXRhX2RhdGEkUFRfTGluZWFnZU1hbGUpCgptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gbWFsZV9icmFuY2hfbWV0YV9kYXRhCgojZmVtYWxlCmZlbWFsZV9icmFuY2hfbWV0YV9kYXRhIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJwcmUtZGV0IiB8IHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gImZlbWFsZSIpLCBdCgpmZW1hbGVfYnJhbmNoX21ldGFfZGF0YSA8LSBkYXRhLmZyYW1lKGNlbGxfaWQgPSByb3duYW1lcyhmZW1hbGVfYnJhbmNoX21ldGFfZGF0YSksIHB0ID0gZmVtYWxlX2JyYW5jaF9tZXRhX2RhdGEkUFRfTGluZWFnZUZlbWFsZSkKCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGZlbWFsZV9icmFuY2hfbWV0YV9kYXRhCgojIyB3aGF0J3MgdGhlIHJhbmdlIG9mIHZhbHVlcyBmb3IgZWFjaCBwdD8KCnJhbmdlKGZlbWFsZV9jZWxsX2dyb3VwX2RmJHB0KQpyYW5nZShtYWxlX2NlbGxfZ3JvdXBfZGYkcHQpCmBgYAoKCmBgYHtyfQojIyBtYWtlIGJpbiB3aWR0aHMKIyBtYWtlIGEgbmV3IGNvbCBmb3IgYW5ub3RhdGlvbgpmZW1hbGVfY2VsbF9ncm91cF9kZiRwdF9iaW4gPC0gTkEKZm9yKGkgaW4gc2VxKDQsNjgsNCkpewogIGZlbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2Jpblt3aGljaChmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCA8IGkgJiBmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCA+PSAoaS00KSldIDwtIGkKfQoKbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2JpbiA8LSBOQQpmb3IoaSBpbiBzZXEoNCw2OCw0KSl7CiAgbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2Jpblt3aGljaChtYWxlX2NlbGxfZ3JvdXBfZGYkcHQgPCBpICYgbWFsZV9jZWxsX2dyb3VwX2RmJHB0ID49IChpLTQpKV0gPC0gaQp9CiMgdGhlbiByZW1vdmUgb2xkIHB0IHZhbHVlcwptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gbWFsZV9jZWxsX2dyb3VwX2RmWyAsLTJdCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGZlbWFsZV9jZWxsX2dyb3VwX2RmWyAsLTJdCmBgYAoKYGBge3J9CiMjIFRoZSBvcmlnaW5hbCBvYmplY3QgY29udGFpbnMgYWxsIGNlbGxzLCB3ZSBqdXN0IHdhbnQgd2lsZC10eXBlIHNvIGxldCdzIHN1YnNldCBvdXQgZ2VuZV9tb2R1bGVfZGYgYW5kIGNlbGxfZ3JvdXBfZGYgYWNjb3JkaW5nbHkKCiMjIG1hbGUKIyMgc3Vic2V0IG91ciBjZWxsIGdyb3VwIGRmIHRvIGtlZXAgb25seSB0aGVzZSBjZWxscwptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gbWFsZV9jZWxsX2dyb3VwX2RmW3doaWNoKG1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkICVpbiUgbWFsZV9jZWxscyksXQojIyBtYWtlIGEgbmV3IGRhdGFmcmFtZSBmb3IgY2VsbCBncm91cHMgLSBpdCBpcyBjcnVjaWFsIHRvIHJlZmFjdG9yIG90aGVyd2lzZSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uIHRoaW5rcyBpdCdzIG91dCBvZiBib3VuZHMgIAptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gZGF0YS5mcmFtZShjZWxsPWFzLmNoYXJhY3RlcihmYWN0b3IobWFsZV9jZWxsX2dyb3VwX2RmJGNlbGxfaWQpKSwgY2VsbF9ncm91cD1mYWN0b3IobWFsZV9jZWxsX2dyb3VwX2RmJHB0X2JpbikpICAKIyMgYWdncmVnYXRlIGV4cHJlc3Npb24KbWFsZV9hZ2dfbWF0IDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24obWFsZS5tb25vY2xlLm9iamVjdCwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBtYWxlX2NlbGxfZ3JvdXBfZGYsIGV4Y2x1ZGUubmEgPSBGQUxTRSkKCiMjIGZlbWFsZQojIyBzdWJzZXQgb3V0IG9ubHkgbWFsZSBhbmQgcHJlIGRldGVybWluYXRpb24gY2VsbHMKIyMgc3Vic2V0IG91ciBjZWxsIGdyb3VwIGRmIHRvIGtlZXAgb25seSB0aGVzZSBjZWxscwpmZW1hbGVfY2VsbF9ncm91cF9kZiA8LSBmZW1hbGVfY2VsbF9ncm91cF9kZlt3aGljaChmZW1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkICVpbiUgZmVtYWxlX2NlbGxzKSxdCiMjIG1ha2UgYSBuZXcgZGF0YWZyYW1lIGZvciBjZWxsIGdyb3VwcyAtIGl0IGlzIGNydWNpYWwgdG8gcmVmYWN0b3Igb3RoZXJ3aXNlIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24gdGhpbmtzIGl0J3Mgb3V0IG9mIGJvdW5kcyAgCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGRhdGEuZnJhbWUoY2VsbD1hcy5jaGFyYWN0ZXIoZmFjdG9yKGZlbWFsZV9jZWxsX2dyb3VwX2RmJGNlbGxfaWQpKSwgY2VsbF9ncm91cD1mYWN0b3IoZmVtYWxlX2NlbGxfZ3JvdXBfZGYkcHRfYmluKSkgIAojIyBhZ2dyZWdhdGUgZXhwcmVzc2lvbgpmZW1hbGVfYWdnX21hdCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKGZlbWFsZS5tb25vY2xlLm9iamVjdCwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBmZW1hbGVfY2VsbF9ncm91cF9kZiwgZXhjbHVkZS5uYSA9IEZBTFNFKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gNX0KIyMgdXNlIHRoZXNlIGNsdXN0ZXJzIHRvIHJlb3JkZXIgdGhlIG1vZHVsZXMKbWFsZV9hZ2dfbWF0IDwtIG1hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtYWxlX2FnZ19tYXQpKSwgXQpmZW1hbGVfYWdnX21hdCA8LSBmZW1hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhmZW1hbGVfYWdnX21hdCkpLCBdCgpwaGVhdG1hcDo6cGhlYXRtYXAobWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJyb3ciLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UpCgpwaGVhdG1hcDo6cGhlYXRtYXAoZmVtYWxlX2FnZ19tYXQsIAogICAgICAgICAgICAgICAgICAgc2NhbGU9InJvdyIsCiAgICAgICAgICAgICAgICAgICAjY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSkKCmBgYAoKCgojIyMjIGV4cHJlc3Npb24gb2YgbW9kdWxlcyBpbiBtdXRhbnQgY2VsbHMgKHNpZGUgcGFuZWxzKQoKbWFsZQpgYGB7cn0KIyMgbWFrZSBtb25vY2xlIG9iamVjdCB3aXRoIG11dGFudHMKIyMgZXh0cmFjdCBkYXRhCm11dGFudF9jZWxsc19tYWxlIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkZ2Vub3R5cGVfY29tYmluZWQgPT0gIk11dGFudCIgJiB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJtYWxlIiksXSkKCiMjIG1ha2UgYSBuZXcgU2V1cmF0IG9mIHRoaXMKc2V1cmF0Lm9iamVjdCA8LVN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gbXV0YW50X2NlbGxzX21hbGUpCgojIyBtYWtlIG5ldyBjb3VudHMgYW5kIHBoZW5vOgojIyB0aGUgcmVhc29uIHdlIHVzZSB0aGUgaW50ZWdyYXRlZCBhbmQgdGhlbiBzdWJzZXR0ZWQgaXMgYmVjYXVzZSB0aGVzZSBjZWxscyBoYXZlIGJlZW4gbm9ybWFsaXNlZCB3aGVyZWFzIHRoZSBjZWxscyBpbiBwYl9zZXhfZmlsdGVyZWQgaGF2ZSBub3QgYmVlbiBub3JtYWxpc2VkICh3ZWxsIHRoZXkgaGF2ZSBidXQgd2l0aCBkb3VibGV0cyBpbiB0aGVtKQpkYXRhIDwtIGFzKGFzLm1hdHJpeChHZXRBc3NheURhdGEoc2V1cmF0Lm9iamVjdCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikpLCAnc3BhcnNlTWF0cml4JykKcGQgPC0gZGF0YS5mcmFtZShzZXVyYXQub2JqZWN0QG1ldGEuZGF0YSkKZkRhdGEgPC0gZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSByb3cubmFtZXMoZGF0YSksIHJvdy5uYW1lcyA9IHJvdy5uYW1lcyhkYXRhKSkKCiMjIENvbnN0cnVjdCBtb25vY2xlIGNkcwptb25vY2xlLm9iamVjdC5tdXRhbnRzLm1hbGUgPC0gbmV3X2NlbGxfZGF0YV9zZXQoZXhwcmVzc2lvbl9kYXRhID0gZGF0YSwgY2VsbF9tZXRhZGF0YSA9IHBkLCBnZW5lX21ldGFkYXRhID0gZkRhdGEpCgojIyBwcmVwcm9jZXNzCm1vbm9jbGUub2JqZWN0Lm11dGFudHMubWFsZSA9IHByZXByb2Nlc3NfY2RzKG1vbm9jbGUub2JqZWN0Lm11dGFudHMubWFsZSwgbnVtX2RpbSA9IDUwLCBub3JtX21ldGhvZCA9ICJub25lIikKIyMjIGlmIHVzaW5nIGludGVncmF0ZWQgZGF0YToKIyBub3JtX21ldGhvZCA9ICJub25lIiwgYWxpZ25tZW50X2dyb3VwID0gIn4gZXhwZXJpbWVudCIKCiMjIG1ha2UgYSBjZWxsIGdyb3VwIGRhdGFmcmFtZSBmb3IgYWdncmVnYXRpbmcgZXhwcmVzc2lvbiB2YWx1ZXM6CgptdXRhbnRfY2VsbF9ncm91cF9kZiA8LSBkYXRhLmZyYW1lKGNlbGwgPSByb3cubmFtZXMobW9ub2NsZS5vYmplY3QubXV0YW50cy5tYWxlQGNvbERhdGEpLCBjZWxsX2dyb3VwID0gbW9ub2NsZS5vYmplY3QubXV0YW50cy5tYWxlQGNvbERhdGEkaWRlbnRpdHlfdXBkYXRlZCkKCiMjIGFnZ3JlZ2F0ZSBleHByZXNzaW9uCm11dGFudF9tYWxlX2FnZ19tYXQgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdC5tdXRhbnRzLm1hbGUsIGdlbmVfbW9kdWxlX2RmX3NleCwgbXV0YW50X2NlbGxfZ3JvdXBfZGYpCmBgYAoKcGxvdApgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDV9Cm11dGFudF9tYWxlX2FnZ19tYXQgPC0gbXV0YW50X21hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtdXRhbnRfbWFsZV9hZ2dfbWF0KSksIF0KCnBoZWF0bWFwOjpwaGVhdG1hcChtdXRhbnRfbWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJjb2x1bW4iLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDV9Cm11dGFudF9tYWxlX2FnZ19tYXQgPC0gbXV0YW50X21hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtdXRhbnRfbWFsZV9hZ2dfbWF0KSksIF0KCnBoZWF0bWFwOjpwaGVhdG1hcChtdXRhbnRfbWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJjb2x1bW4iLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgpmZW1hbGUKYGBge3J9CiMjIG1ha2UgbW9ub2NsZSBvYmplY3Qgd2l0aCBtdXRhbnRzCiMjIGV4dHJhY3QgZGF0YQptdXRhbnRfY2VsbHNfZmVtYWxlIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkZ2Vub3R5cGVfY29tYmluZWQgPT0gIk11dGFudCIgJiB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJmZW1hbGUiKSxdKQoKIyMgbWFrZSBhIG5ldyBTZXVyYXQgb2YgdGhpcwpzZXVyYXQub2JqZWN0IDwtU3Vic2V0RGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgY2VsbHMgPSBtdXRhbnRfY2VsbHNfZmVtYWxlKQoKIyMgbWFrZSBuZXcgY291bnRzIGFuZCBwaGVubzoKIyMgdGhlIHJlYXNvbiB3ZSB1c2UgdGhlIGludGVncmF0ZWQgYW5kIHRoZW4gc3Vic2V0dGVkIGlzIGJlY2F1c2UgdGhlc2UgY2VsbHMgaGF2ZSBiZWVuIG5vcm1hbGlzZWQgd2hlcmVhcyB0aGUgY2VsbHMgaW4gcGJfc2V4X2ZpbHRlcmVkIGhhdmUgbm90IGJlZW4gbm9ybWFsaXNlZCAod2VsbCB0aGV5IGhhdmUgYnV0IHdpdGggZG91YmxldHMgaW4gdGhlbSkKZGF0YSA8LSBhcyhhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKHNldXJhdC5vYmplY3QsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCnBkIDwtIGRhdGEuZnJhbWUoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpCmZEYXRhIDwtIGRhdGEuZnJhbWUoZ2VuZV9zaG9ydF9uYW1lID0gcm93Lm5hbWVzKGRhdGEpLCByb3cubmFtZXMgPSByb3cubmFtZXMoZGF0YSkpCgojIyBDb25zdHJ1Y3QgbW9ub2NsZSBjZHMKbW9ub2NsZS5vYmplY3QubXV0YW50cy5mZW1hbGUgPC0gbmV3X2NlbGxfZGF0YV9zZXQoZXhwcmVzc2lvbl9kYXRhID0gZGF0YSwgY2VsbF9tZXRhZGF0YSA9IHBkLCBnZW5lX21ldGFkYXRhID0gZkRhdGEpCgojIyBwcmVwcm9jZXNzCm1vbm9jbGUub2JqZWN0Lm11dGFudHMuZmVtYWxlID0gcHJlcHJvY2Vzc19jZHMobW9ub2NsZS5vYmplY3QubXV0YW50cy5mZW1hbGUsIG51bV9kaW0gPSA1MCwgbm9ybV9tZXRob2QgPSAibm9uZSIpCiMjIyBpZiB1c2luZyBpbnRlZ3JhdGVkIGRhdGE6CiMgbm9ybV9tZXRob2QgPSAibm9uZSIsIGFsaWdubWVudF9ncm91cCA9ICJ+IGV4cGVyaW1lbnQiCgojIyBtYWtlIGEgY2VsbCBncm91cCBkYXRhZnJhbWUgZm9yIGFnZ3JlZ2F0aW5nIGV4cHJlc3Npb24gdmFsdWVzOgptdXRhbnRfY2VsbF9ncm91cF9kZiA8LSBkYXRhLmZyYW1lKGNlbGwgPSByb3cubmFtZXMobW9ub2NsZS5vYmplY3QubXV0YW50cy5mZW1hbGVAY29sRGF0YSksIGNlbGxfZ3JvdXAgPSBtb25vY2xlLm9iamVjdC5tdXRhbnRzLmZlbWFsZUBjb2xEYXRhJGlkZW50aXR5X3VwZGF0ZWQpCgojIyBhZ2dyZWdhdGUgZXhwcmVzc2lvbgptdXRhbnRfZmVtYWxlX2FnZ19tYXQgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdC5tdXRhbnRzLmZlbWFsZSwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBtdXRhbnRfY2VsbF9ncm91cF9kZikKYGBgCgpwbG90CmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gNX0KbXV0YW50X2ZlbWFsZV9hZ2dfbWF0IDwtIG11dGFudF9mZW1hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtdXRhbnRfZmVtYWxlX2FnZ19tYXQpKSwgXQoKcGhlYXRtYXA6OnBoZWF0bWFwKG11dGFudF9mZW1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0iY29sdW1uIiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gNX0KbXV0YW50X2ZlbWFsZV9hZ2dfbWF0IDwtIG11dGFudF9mZW1hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtdXRhbnRfZmVtYWxlX2FnZ19tYXQpKSwgXQoKcGhlYXRtYXA6OnBoZWF0bWFwKG11dGFudF9mZW1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKIyMjIyBmb3IgcGFydGljdWxhciBnZW5lcyAobG93ZXIgcGFuZWwpCgpgYGB7ciwgZmlnLmhlaWdodCA9IDIsIGZpZy53aWR0aCA9IDl9CiMjIGxhbmRtYXJrIGdlbmVzIChnZW5lcyBvZiBpbnRlcmVzdCkKIyBBUDJHIC0gUEJBTktBLTE0Mzc1MDAKIyBBUDIgLSBQQkFOS0EtMDkwOTYwMCAtIGZyb20gcG9yYW4gcGFwZXIKIyBBUDJHLTIgLSBQQkFOS0EtMTAzNDMwMCAKbGlzdF9vZl9tdXRhbnRfZ2VuZXMgPC0gYygiUEJBTktBLTA4MjgwMDAiLCAiUEJBTktBLTEzMDI3MDAiLCAiUEJBTktBLTE0NDc5MDAiLCAiUEJBTktBLTAxMDI0MDAiLCAiUEJBTktBLTA3MTY1MDAiLCAiUEJBTktBLTE0MzUyMDAiLCAiUEJBTktBLTE0MTgxMDAiLCAiUEJBTktBLTExNDQ4MDAiLCAiUEJBTktBLTA5MDIzMDAiLCAiUEJBTktBLTA0MTM0MDAiLCAiUEJBTktBLTE0NTQ4MDAiKQoKbGlzdF9vZl9nZW5lc19vZl9pbnRlcmVzdCA8LSBjKCJQQkFOS0EtMTQzNzUwMCIsICJQQkFOS0EtMDkwOTYwMCIsIlBCQU5LQS0xMDM0MzAwIiwgIlBCQU5LQS0wODI4MDAwIiwgIlBCQU5LQS0xMzAyNzAwIiwgIlBCQU5LQS0xNDQ3OTAwIiwgIlBCQU5LQS0wMTAyNDAwIiwgIlBCQU5LQS0wNzE2NTAwIiwgIlBCQU5LQS0xNDM1MjAwIiwgIlBCQU5LQS0xNDE4MTAwIiwgIlBCQU5LQS0xMTQ0ODAwIiwgIlBCQU5LQS0wOTAyMzAwIiwgIlBCQU5LQS0wNDEzNDAwIiwgIlBCQU5LQS0xNDU0ODAwIikKIyNtYWtlIGRmIGZvciBnZW5lcyBvZiBpbnRlcmVzdApnZW5lc19vZl9pbnRlcmVzdCA8LSBkYXRhLmZyYW1lKGdlbmUgPSBsaXN0X29mX2dlbmVzX29mX2ludGVyZXN0LCBncm91cCA9IGMoMTpsZW5ndGgobGlzdF9vZl9nZW5lc19vZl9pbnRlcmVzdCkpKQoKIyMgYWdncmVnYXRlIGV4cHJlc3Npb24KIyMgbWFrZSBwbG90dGluZyBkZgphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24obW9ub2NsZS5vYmplY3QsIGdlbmVzX29mX2ludGVyZXN0LCBjZWxsX2dyb3VwX2RmKQoKcm93Lm5hbWVzKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QpIDwtIGdlbmVzX29mX2ludGVyZXN0JGdlbmUKCiNyb3cubmFtZXMoYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCkgPC0gZmFjdG9yKHJvdy5uYW1lcyhhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0KSwgbGV2ZWxzID0gcm93Lm5hbWVzKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QpW21vZHVsZV9kZW5kcm8kb3JkZXJdKQphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3RbLG1hdGNoKHJvd25hbWVzKGNsdXN0ZXJfYW5ubyksIGNvbG5hbWVzKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QpKV0KCnBoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJyb3ciLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGNsdXN0ZXJfYW5ubywgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycykKYGBgCgpjb21wbGV4IGhlYXQgbWFwCgpgYGB7cn0KIyMgYWdncmVnYXRlIGdlbmUgZXhwcmVzc2lvbgphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24obW9ub2NsZS5vYmplY3QsIGdlbmVzX29mX2ludGVyZXN0LCBkZl9hbGxfY2VsbHMpCgphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFzLm1hdHJpeChhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0KQoKIyMgbWFrZSBoZWF0bWFwCm1vZHVsZXNfaGVhdG1hcCA8LSBIZWF0bWFwKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsCiAgICAgICAgY29sdW1uX2xhYmVscyA9IHJlcCgiIiwgbmNvbChhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXgpKSwKICAgICAgICAjcm93X29yZGVyID0gbW9kdWxlX2RlbmRybyRvcmRlciwKICAgICAgICBjbHVzdGVyaW5nX21ldGhvZF9jb2x1bW5zID0gIndhcmQuRDIiLAogICAgICAgIGJvdHRvbV9hbm5vdGF0aW9uID0gaGVhdG1hcF9hbm5vdGF0aW9uLAogICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPQogICJSZFlsQnUiKSkpKDEwMCksIAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpKQoKIyMgcHJpbnQKZHJhdyhtb2R1bGVzX2hlYXRtYXAsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmBgYAoKYGBge3J9CiMjIG9yZGVyIGNvbHMgaW4gdGhlIG1hdHJpeAphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3RbICxtYXRjaChyb3duYW1lcyhkZl9hbm5vKSwgY29sbmFtZXMoYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCkpXQoKIyMgbWFrZSBoZWF0bWFwCm1vZHVsZXNfaGVhdG1hcCA8LSBIZWF0bWFwKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fbGFiZWxzID0gcmVwKCIiLCBuY29sKGFnZ19tYXRfYWxsX2NlbGxzX21hdHJpeCkpLAogICAgICAgICNyb3dfb3JkZXIgPSBtb2R1bGVfZGVuZHJvJG9yZGVyLAogICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kX2NvbHVtbnMgPSAid2FyZC5EMiIsCiAgICAgICAgYm90dG9tX2Fubm90YXRpb24gPSBoZWF0bWFwX2Fubm90YXRpb24sCiAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9CiAgIlJkWWxCdSIpKSkoMTAwKSwgCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikpCgojIyBwcmludApkcmF3KG1vZHVsZXNfaGVhdG1hcCwgbWVyZ2VfbGVnZW5kID0gVFJVRSwgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iLCAKICAgIGFubm90YXRpb25fbGVnZW5kX3NpZGUgPSAiYm90dG9tIikKYGBgCgpVc2luZyBTZXVyYXQgdG8gdmlzdWFsaXNlIGNlbGxzCmBgYHtyfQojIGZpbmQgbWFya2VycyBmb3IgZXZlcnkgY2x1c3RlciBjb21wYXJlZCB0byBhbGwgcmVtYWluaW5nIGNlbGxzLCByZXBvcnQgb25seSB0aGUgcG9zaXRpdmUgb25lcwp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleC5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBvbmx5LnBvcyA9IFRSVUUsIG1pbi5wY3QgPSAwLjI1LCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1KQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleC5tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24obiA9IDIsIHd0ID0gYXZnX2xvZ0ZDKQpgYGAKCmBgYHtyfQp0b3AxMCA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleC5tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24obiA9IDEwLCB3dCA9IGF2Z19sb2dGQykKRG9IZWF0bWFwKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBmZWF0dXJlcyA9IHRvcDEwJGdlbmUpICsgTm9MZWdlbmQoKQpgYGAKCkJ1dCB3ZSBhbHNvIGhhdmUgdGhlIG9sZCBwdCB2YWx1ZXMgdGhhdCB3ZSBjYW4gdXNlIGluIHRoZSBzZXVyYXQgb2JqZWN0IGllIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAicGNhIiwgcHQuc2l6ZSA9IDAuMDEsIGZlYXR1cmVzID0gIm9sZF9wdF92YWx1ZXMiKQoKU28gbGV0J3MgcGxvdCBhIGhlYXRtYXAgd2hlcmUgd2UgcGxvdDogKHgpIGFsbCBjZWxscyB2cy4gKHkpIGdlbmVzIGFycmFuZ2VkIGJ5IG1vZHVsZSB0aGF0IHRoZXkgYmVsb25nIHRvLiAKCmFkZCBhbiBvbGQgcHQgYW5ub3RhdGlvbiB0byB0aGUgdG9wCgpwcmVwYXJlIGRhdGE6CmBgYHtyfQojIyBleHRyYWN0cyBvbmx5IDEweCBjZWxscyAKd3RfY2VsbHMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1RfMTBYIiksXSkKCiMjIG1ha2UgYSBuZXcgU2V1cmF0IG9mIHRoaXMKc2V1cmF0Lm9iamVjdCA8LVN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gd3RfY2VsbHMpCmBgYAoKYGBge3J9CkRvSGVhdG1hcChzZXVyYXQub2JqZWN0LCBmZWF0dXJlcyA9IHRvcDEwJGdlbmUpICsgTm9MZWdlbmQoKQpgYGAKCmBgYHtyfQoKYGBgCgoKYGBge3J9CiMjIGFnZ3JlZ2F0ZSBnZW5lIGV4cHJlc3Npb24KYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1vbm9jbGUub2JqZWN0LCBnZW5lc19vZl9pbnRlcmVzdCwgZGZfYWxsX2NlbGxzKQoKYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCA8LSBhcy5tYXRyaXgoYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCkKCiMjIG1ha2UgaGVhdG1hcAptb2R1bGVzX2hlYXRtYXAgPC0gSGVhdG1hcChhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0LAogICAgICAgIGNvbHVtbl9vcmRlciA9IE5VTEwsCiAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgc2hvd19jb2x1bW5fZGVuZCA9IEZBTFNFLAogICAgICAgIGNvbHVtbl9sYWJlbHMgPSByZXAoIiIsIG5jb2woYWdnX21hdF9hbGxfY2VsbHNfbWF0cml4KSksCiAgICAgICAgI3Jvd19vcmRlciA9IG1vZHVsZV9kZW5kcm8kb3JkZXIsCiAgICAgICAgY2x1c3RlcmluZ19tZXRob2RfY29sdW1ucyA9ICJ3YXJkLkQyIiwKICAgICAgICBib3R0b21fYW5ub3RhdGlvbiA9IGhlYXRtYXBfYW5ub3RhdGlvbiwKICAgICAgICBjb2wgPSBjb2xvclJhbXBQYWxldHRlKHJldihicmV3ZXIucGFsKG4gPSA3LCBuYW1lID0KICAiUmRZbEJ1IikpKSgxMDApLCAKICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoZGlyZWN0aW9uID0gImhvcml6b250YWwiKSkKCiMjIHByaW50CmRyYXcobW9kdWxlc19oZWF0bWFwLCBtZXJnZV9sZWdlbmQgPSBUUlVFLCBoZWF0bWFwX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIsIAogICAgYW5ub3RhdGlvbl9sZWdlbmRfc2lkZSA9ICJib3R0b20iKQpgYGAKCkV4cHJlc3Npb24gb2YgQ0NQMiBhbmQgTUcxIGJ5IGVhY2ggZ2Vub3R5cGUgYW5kIGVhY2ggc2V4CgpgYGB7cn0KIyBjY3AyIC0gIlBCQU5LQS0xMzE5NTAwIiAtIGZlbWFsZSA4MjAKIyBNRzEgLSAiUEJBTktBLTA0MTYxMDAiIC0gbWFsZSA4MjAKCiMjIG1ha2UgYSBjdXN0b20gZGF0YWZyYW1lOgptYXJrZXJfODIwX2RmIDwtIGFzLmRhdGEuZnJhbWUodChhcy5kYXRhLmZyYW1lKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QGFzc2F5cyRSTkFAZGF0YVtjKCJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMDQxNjEwMCIpLCBdLCBzdHJpbmdzQXNGYWN0b3JzPUYpKSkKbWFya2VyXzgyMF9kZiRjZWxsX2lkIDwtIHJvdy5uYW1lcyhtYXJrZXJfODIwX2RmKQpzZXhfaWQgPC0gZGF0YS5mcmFtZShzZXhfYXQgPSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkYXRfc2V4LCBnZW5vdHlwZSA9IHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkICxjZWxsX2lkID0gcm93Lm5hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSkpCm1hcmtlcl84MjBfZGYgPC0gbWVyZ2UobWFya2VyXzgyMF9kZiwgc2V4X2lkLCBieSA9ICJjZWxsX2lkIikKCmdncGxvdChtYXJrZXJfODIwX2RmLCBhZXMoZmlsbD1zZXhfYXQsIHk9YFBCQU5LQS0xMzE5NTAwYCwgeD1nZW5vdHlwZSkpICsgCiAgICBnZW9tX3Zpb2xpbigpICsKICBnZW9tX2ppdHRlcihzaGFwZT0xNiwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKDAuMikpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQpgYGAKCmBgYHtyfQojdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gInByZS1kZXQiIHwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAiZmVtYWxlIiksIF0KCgpWbG5QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBncm91cC5ieSA9ICJpZGVudGl0eV91cGRhdGVkIiwgc3BsaXQuYnkgPSAiYXRfc2V4IiwgZmVhdHVyZXMgPSBjKCJQQkFOS0EtMTMxOTUwMCIpLCBzcGxpdC5wbG90ID0gVFJVRSkKClZsblBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGdyb3VwLmJ5ID0gImlkZW50aXR5X3VwZGF0ZWQiLCBzcGxpdC5ieSA9ICJhdF9zZXgiLCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0wNDE2MTAwIiksIHNwbGl0LnBsb3QgPSBUUlVFKQpgYGAKCkRpZmZlcmVudGlhbCBleHByZXNzaW9uCgpSZS1jbHVzdGVyIHRoZSBkYXRhIHNvIHdlIGhhdmUgdmVyeSBjb3Vyc2UgZ3JhaW4gY2x1c3RlcnMKYGBge3J9CiMjIGZpbmQgbmV3IGNsdXN0ZXJzCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgcmVzb2x1dGlvbiA9IDEsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCgojIyBwbG90IHRoZSBncmFwaApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMSIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKYGBge3J9ClZsblBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGZlYXR1cmVzID0gYygiUFRfRmVtYWxlX1VNQVAiLCAiUFRfTWFsZV9VTUFQIikpCmBgYAoKIyMjIyBTaG93IHJlcHJlc2VudGF0aW9uIG9mIGdlbm90eXBlcyBwZXIgY2x1c3RlcgoKcHJlcCBmb3IgZG90cGxvdApgYGB7cn0KIyMgbWFrZSBhIGRhdGFmcmFtZSB0aGF0IGlzIHRoZSBtZXRhIGRhdGEKZGZfbWV0YV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhKQoKIyMgZGVmaW5lIG9yZGVyIGZvciBwbG90dGluZyAKbXlfbGV2ZWxzX3NleCA8LSBjKCIyIiwgIjMiLCAiOSIsICI2IiwgIjExIiwgIjUiLCAiMCIsICIxMCIsICIxMyIsICIxNCIsICIxMiIsICI4IiwgIjE1IiwgIjEiLCAiNCIsICI3IikKCiMjIHJlZGVmaW5lIG9yZGVyIG9mIGNsdXN0ZXJzOgpkZl9tZXRhX2RhdGEkc2V1cmF0X2NsdXN0ZXJzIDwtIGZhY3Rvcih4ID0gZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgbGV2ZWxzID0gbXlfbGV2ZWxzX3NleCkKCiMjIG1ha2UgYSBuZXcgZGYgb2YgQ0xVU1RFUiBhbmQgSURFTlRJVFkKZG90X3Bsb3RfZGYgPC0gYXMuZGF0YS5mcmFtZS5tYXRyaXgodGFibGUoZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgZGZfbWV0YV9kYXRhJGlkZW50aXR5X2NvbWJpbmVkKSkKZG90X3Bsb3RfZGYkY2x1c3RlciA8LSByb3duYW1lcyhkb3RfcGxvdF9kZikKCiMjIGNhbGN1bGF0ZSBwZXJjZW50YWdlIG9mIGNlbGxzIGZvciBlYWNoIGdlbm90eXBlCmRvdF9wbG90X2RmX3BjIDwtIChhcy5kYXRhLmZyYW1lLm1hdHJpeChwcm9wLnRhYmxlKHRhYmxlKGRmX21ldGFfZGF0YSRzZXVyYXRfY2x1c3RlcnMsIGRmX21ldGFfZGF0YSRpZGVudGl0eV9jb21iaW5lZCksIG1hcmdpbiA9IDIpKSAqIDEwMCkKCiMjIG1ha2UgYSBjb2x1bW4gZm9yIGNsdXN0ZXIgbmFtZXMKZG90X3Bsb3RfZGZfcGMkY2x1c3RlciA8LSByb3duYW1lcyhkb3RfcGxvdF9kZl9wYykKCiMjIG1lbHQgZGF0YWZyYW1lIGZvciBwbG90dGluZwpsaWJyYXJ5KHJlc2hhcGUyKQpkb3RfcGxvdF9kZl9wY19tZWx0ZWQgPC0gbWVsdChkb3RfcGxvdF9kZl9wYywgdmFyaWFibGUubmFtZSA9ICJjbHVzdGVyIikKY29sbmFtZXMoZG90X3Bsb3RfZGZfcGNfbWVsdGVkKVsyXSA8LSAiaWRlbnRpdHkiCgojIyBtZWx0IHRoZSByYXcgbnVtYmVyIHRvbwpkb3RfcGxvdF9kZl9tZWx0ZWQgPC0gbWVsdChkb3RfcGxvdF9kZiwgdmFyaWFibGUubmFtZSA9ICJjbHVzdGVyIikKY29sbmFtZXMoZG90X3Bsb3RfZGZfbWVsdGVkKVsyXSA8LSAiaWRlbnRpdHkiCmNvbG5hbWVzKGRvdF9wbG90X2RmX21lbHRlZClbM10gPC0gInJhd19udW1iZXIiCgojIyBtZXJnZSB0b2dldGhlcgppZGVudGljYWwoZG90X3Bsb3RfZGZfbWVsdGVkJGNsdXN0ZXIsIGRvdF9wbG90X2RmX3BjX21lbHRlZCRjbHVzdGVyKQpkb3RfcGxvdF9tZXJnZWQgPC0gY2JpbmQoZG90X3Bsb3RfZGZfbWVsdGVkLCBkb3RfcGxvdF9kZl9wY19tZWx0ZWQpCmRvdF9wbG90X21lcmdlZCA8LSBkb3RfcGxvdF9tZXJnZWRbLGMoMSwyLDMsNildCgojIyByZWRlZmluZSBvcmRlciBvZiBjbHVzdGVycwpkb3RfcGxvdF9tZXJnZWQkY2x1c3RlciA8LSBmYWN0b3IoeCA9IGRvdF9wbG90X21lcmdlZCRjbHVzdGVyLCBsZXZlbHMgPSBteV9sZXZlbHNfc2V4KQoKIyMgd2hlcmUgdmFsdWVzIGFyZSB6ZXJvLCBhZGQgTkEKIyMgZmluZCB3ZWxscyB3aGVyZSBpdCdzIHplcm8KemVyb192YWx1ZXMgPC0gZG90X3Bsb3RfbWVyZ2VkJHZhbHVlID09IDAKZG90X3Bsb3RfbWVyZ2VkJHZhbHVlW3plcm9fdmFsdWVzXSA8LSBOQQoKIyMgYWxzbyBkbyBmb3IgcmF3IG51bWJlcgp6ZXJvX3ZhbHVlcyA8LSBkb3RfcGxvdF9tZXJnZWQkcmF3X251bWJlciA9PSAwCmRvdF9wbG90X21lcmdlZCRyYXdfbnVtYmVyW3plcm9fdmFsdWVzXSA8LSBOQQoKIyMgcmVvcmRlciB4IGF4aXM6Cm15X2xldmVsc19nZW5vdHlwZSA8LSBjKCJHQ1NLTy1vb20iLCAiR0NTS08tMjkiLCAiR0NTS08tMiIsICJHQ1NLTy0xOSIsICJHQ1NLTy0zIiwgIkdDU0tPLTIxIiwgIkdDU0tPLTEzIiwgIkdDU0tPLTI4IiwgIkdDU0tPLTEwXzgyMCIsICJHQ1NLTy0xNyIsICJHQ1NLTy0yMCIsICJXVCIsICJXVF8xMFgiKQoKZG90X3Bsb3RfbWVyZ2VkJGlkZW50aXR5IDwtIGZhY3Rvcih4ID0gZG90X3Bsb3RfbWVyZ2VkJGlkZW50aXR5LCBsZXZlbHMgPSBteV9sZXZlbHNfZ2Vub3R5cGUpCmBgYAoKcGxvdApgYGB7ciwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodD0gN30KIyMgcGxvdApkb3RfcGxvdF9pZGVudGl0eSA8LSBnZ3Bsb3QoZG90X3Bsb3RfbWVyZ2VkLCBhZXMoeSA9IGZhY3RvcihjbHVzdGVyKSwgeCA9IGZhY3RvcihpZGVudGl0eSkpKSArCiAgICAgICMjIG1ha2UgaW50byBhIGRvdCBwbG90CiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG91cj12YWx1ZSwgc2l6ZT1yYXdfbnVtYmVyKSkgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93PSJibHVlIiwgaGlnaD0icmVkIiwgbGltaXRzPWMoIDAsIG1heChkb3RfcGxvdF9kZl9wY19tZWx0ZWQkdmFsdWUpKSwgbmEudmFsdWU9IndoaXRlIikgKwogICAgICAjY2hhbmdlIHRoZSBjb2xvdXJzCiAgICAgIHNjYWxlX2NvbG91cl92aXJpZGlzKG9wdGlvbiA9ICJpbmZlcm5vIiwgZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIikgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCksIHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYsICBmYW1pbHk9IkFyaWFsIikpICsKICAgICAgeWxhYigiQ2x1c3RlciIpICsKICAgICAgeGxhYigiSWRlbnRpdHkiKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEyLCBhbmdsZT00NSwgaGp1c3Q9MSwgdmp1c3Q9MSksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyLCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBwbG90Lm1hcmdpbiA9IHVuaXQoYygxLDMsMSwzKSwgImxpbmVzIikpICsKICAgICMjIGFubm90YXRlIG1hbGVzCiAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMi41KSkgKwogICAgIyMgYW5ub3RhdGUgZmVtYWxlcwogICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDcuNSkpICsKICAgICMjIGFubm90YXRlIHBoZW5vIDEKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSA0LjUpKSArCiAgICAjIyBhbm5vdGF0ZSBwaGVubyAyCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gNS41KSkgKyAgICAKICAgICMjIGFubm90YXRlIHBoZW5vIDMKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSA3LjUpKSArCiAgICAjIyBhbm5vdGF0ZSBwaGVubyA0CiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gMTEuNSkpCgojIyBwcmludApwcmludChkb3RfcGxvdF9pZGVudGl0eSkKYGBgCgoKCgpjdXQgb2ZmIGFuZCBwbG90CmBgYHtyfQpwcmVfYnJhbmNoX2NlbGxzIDwtIGMoMiwzKQppbm1hdHVyZV9tYWxlX2NlbGxzIDwtIGMoKQppbm1hdHVyZV9mZW1hbGVfY2VsbHMgPC0KbWF0dXJlX21hbGVfY2VsbHMgPC0gCm1hdHVyZV9mZW1hbGVfY2VsbHMgPC0gCgojIyBwbG90IHRoZSBncmFwaApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMSIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCgoKYGBge3J9Cnd0X2NlbGxzIDwtIHJvdy5uYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVCIgfCB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkaWRlbnRpdHlfY29tYmluZWQgPT0gIldUXzEwWCIpLCBdKQoKbWFsZV9pbm1hdHVyZV9jZWxscyA8LSByb3cubmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1QiIHwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVF8xMFgiKSwgXSkKCgoKZWFybHlfd3RfY2VsbHMgPC0gcm93Lm5hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkaWRlbnRpdHlfY29tYmluZWQgPT0gIldUIiAmJiB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkUFRfTGluZWFnZUZlbWFsZSA8IDQ2KSwgXSkKCkZpbmRNYXJrZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBjZWxscy4xID0gLCBjZWxscy4yID0gKQpgYGAKCiMjIyBHZW5lcmF0ZSBOZXcgQ2x1c3RlcnMKCldlIG11c3Qgbm93IHJlY2FsY3VsYXRlIHRoZSBjbHVzdGVycyB0byBnYWluIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIGhldGVyb2dlbmVpdHkgb2YgdGhlIHN1YnNldC4gU2luY2UgdXNpbmcgdGhlIHByZXZpb3VzIGNsdXN0ZXJzLCB0aGUgYXNleHVhbCBjZWxscyBvYnNjdXJlZCBzb21lIG9mIHRoZSB2YXJpYXRpb24uIAoKYGBge3J9CiMjIGNvcHkgb2xkIGNsdXN0ZXJzCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIEFkZE1ldGFEYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzLCBjb2wubmFtZSA9ICJwcmVfc2V4X2NsdXN0ZXJzIikKYGBgCgpgYGB7cn0KIyMgZ2VuZXJhdGUgbmV3IGNsdXN0ZXJzIGF0IHZhcmlvdXMgcmVzb2x1dGlvbnMKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXggPC0gRmluZE5laWdoYm9ycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgZGltcyA9IDE6MTUpCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgcmVzb2x1dGlvbiA9IGMoMiwzLDQsNSw2KSwgcmFuZG9tLnNlZWQgPSA0MiwgYWxnb3JpdGhtID0gMikKYGBgCgojIyMgVmlzdWFsaXNlCgojIyMjIENob29zZSBDbHVzdGVyIFJlc29sdXRpb24KClZpZXcgdGhlIGNsdXN0ZXJzIGF0IGRpZmZlcmVudCByZXNvbHV0aW9ucyB0byBjaG9zZSB0aGUgYXBwcm9wcmFpdGUgcmVzb2x1dGlvbgpgYGB7cn0KIyMgcGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMiIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCgpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMyIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCgpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuNCIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCgpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuNSIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCgpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuNiIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKR28gd2l0aCA0IGNsdXN0ZXJzCmBgYHtyfQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCA8LSBGaW5kQ2x1c3RlcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHJlc29sdXRpb24gPSA0LCByYW5kb20uc2VlZCA9IDQyLCBhbGdvcml0aG0gPSAyKQoKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgcmVkdWN0aW9uID0gInVtYXBvcHRpbWlzZWRfcG9zdF9yZXBjYSIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKYGBgCgojIyMjIE9yaWdpbmFsIFVNQVAKCllvdSBjYW4gYWxzbyB1c2UgdGhlIG9yaWdpbmFsIFVNQVAgcHJvamVjdGlvbgpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKYGBgCgojIyMjIFJlcHJlc2VudGF0aW9uCgpsb29rIGF0IGNsdXN0ZXIgcmVwcmVzZW50YXRpb24KYGBge3IsIGVjaG8gPSBGQUxTRX0KIyMgZm9yIGxvb3Agd2hpY2ggdGFrZXMgZWFjaCBjbHVzdGVyIGFuZCBtYWtlcyBhIGxpc3Qgb2YgY2VsbHMgYW5kIHRoZW4gcGxvdHMgYSBoaWdobGlnaHRlZCBwbG90IGFuZCBhZGRzIGl0IHRvIGEgbGlzdAoKIyMgbWFrZSBhIGRmIG9mIHRoZSBudW1iZXIgb2YgCm5fcGVyX2NsdXN0ZXIgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKSkKcm93bmFtZXMobl9wZXJfY2x1c3RlcikgPC0gbl9wZXJfY2x1c3RlciRWYXIxCm5fcGVyX2NsdXN0ZXIgPC0gbl9wZXJfY2x1c3RlclssMl0KCiMjIG1ha2UgYSBibGFuayBsaXN0Cmxpc3RfVU1BUHNfYnlfY2x1c3RlciA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKSkpCgojIyBmb3IgbG9vcApmb3IoaSBpbiBzZXFfYWxvbmcobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSl7CiAgIyMgbWFrZSBhIGxpc3Qgb2YgY2VsbHMKICBsaXN0X29mX2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzID09IGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKVtpXSksIF0pCiAgdW1hcF9wbG90IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gbGlzdF9vZl9jZWxscywgcmVkdWN0aW9uID0gInVtYXBvcHRpbWlzZWRfcG9zdF9yZXBjYSIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJjbHVzdGVyIiwgbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpW2ldLCAiXG4iLCAiKG4gPSAiLCBuX3Blcl9jbHVzdGVyW2ldLCIpIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAjIyBhZGQgdG8gdGhlIGxpc3QKICBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbW2ldXSA8LSB1bWFwX3Bsb3QKfQpgYGAKCnBsb3QKYGBge3J9CiMjIHRoaXMgZnVuY3Rpb24gd3JpdGVzIHRoZSBuZXh0IGJpdCBvZiBjb2RlIGZvciB5b3UKcGxvdHkgPC0gYygpCmZvcihpIGluIHNlcV9hbG9uZyhsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycykpKXsKICBwbG90eSA8LSBwYXN0ZTAocGxvdHksICJsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWyIsIGksICJdXSIsICIgKyAiKQp9CmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxNSwgZmlnLndpZHRoID0gMjB9CiMjIHBsb3QKbGlicmFyeShncmlkRXh0cmEpCmdyaWQuYXJyYW5nZShsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzFdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMl1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzRdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s2XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzddXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbOF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s5XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzEwXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzExXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzEyXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzEzXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE0XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE1XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE2XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE3XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE4XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE5XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzIwXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzIxXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzIyXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzIzXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzI0XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzI1XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzI2XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzI3XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzI4XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzI5XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzMwXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzMxXV0sIG5jb2wgPSA1KQpgYGAKCgpgYGB7cn0KIyMgZm9yIGxvb3Agd2hpY2ggdGFrZXMgZWFjaCBjbHVzdGVyIGFuZCBtYWtlcyBhIGxpc3Qgb2YgY2VsbHMgYW5kIHRoZW4gcGxvdHMgYSBoaWdobGlnaHRlZCBwbG90IGFuZCBhZGRzIGl0IHRvIGEgbGlzdAoKIyMgbWFrZSBhIGRmIG9mIHRoZSBudW1iZXIgb2YgCm5fcGVyX2NsdXN0ZXIgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKSkKcm93bmFtZXMobl9wZXJfY2x1c3RlcikgPC0gbl9wZXJfY2x1c3RlciRWYXIxCm5fcGVyX2NsdXN0ZXIgPC0gbl9wZXJfY2x1c3RlclssMl0KCiMjIG1ha2UgYSBibGFuayBsaXN0Cmxpc3RfVU1BUHNfYnlfY2x1c3RlciA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKSkpCgojIyBmb3IgbG9vcApmb3IoaSBpbiBzZXFfYWxvbmcobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSl7CiAgIyMgbWFrZSBhIGxpc3Qgb2YgY2VsbHMKICBsaXN0X29mX2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzID09IGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKVtpXSksIF0pCiAgdW1hcF9wbG90IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsICByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gbGlzdF9vZl9jZWxscykgKyAKICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoImNsdXN0ZXIiLCBsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycylbaV0sICJcbiIsICIobiA9ICIsIG5fcGVyX2NsdXN0ZXJbaV0sIikiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICMjIGFkZCB0byB0aGUgbGlzdAogIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbaV1dIDwtIHVtYXBfcGxvdAp9CmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxNSwgZmlnLndpZHRoID0gMjB9CiMjIHBsb3QKZ3JpZC5hcnJhbmdlKGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzNdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s1XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzZdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbN11dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s4XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzldXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTBdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTFdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTJdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTNdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTRdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTVdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTZdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTddXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMThdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTldXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjBdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjFdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjJdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjNdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjRdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjVdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjZdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjddXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjhdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjldXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzBdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzFdXSwgbmNvbCA9IDUpCmBgYAoKIyMjIyBTaG93IGNvcnJlc3BvbmRhbmNlIHdpdGggb2xkIGNsdXN0ZXJzIChBbGx1dml1bSBwbG90LCBTYW5rZXkgZGlhZ3JhbSkKCmBgYHtyfQojI1RoaXMgaXMgdGhlIHNldCB1cCBmb3IgdGhpczoKIyMgdHdvIGNsdXN0ZXJzIHRoYXQgZGlmZmVyCnRhYmxlKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMsIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRwcmVfc2V4X2NsdXN0ZXJzKQpgYGAKCmBgYHtyfQojIyBoZW1iZXJnIHVzZXMgZ3Zpc1NhbmtleSBpbiBodHRwczovL2dpdGh1Yi5jb20vaGVtYmVyZy1sYWIvc2NtYXAvYmxvYi8zYWEyYmI0ODdhODBhOTQ2NDY5MzkzODU3Y2VhNmE2ZWZmYzYxOGZiL1IvVXRpbHMuUiBjb2RlIC0gc28gbWF5YmUgdXBkYXRlIHdpdGggdGhpcz8KCiMjIG1ha2UgYSBkYXRhZnJhbWUgdGhhdCBpcyB0aGUgbWV0YSBkYXRhCmRmX21ldGFfZGF0YSA8LSBhcy5kYXRhLmZyYW1lKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSkKCmRmX2FsbHV2aWFsIDwtIG1lbHQodGFibGUoZGF0YS5mcmFtZShmdWxsX2NsdXN0ZXJzID0gZGZfbWV0YV9kYXRhJHByZV9zZXhfY2x1c3RlcnMsIHNleF9jbHVzdGVycyA9IGRmX21ldGFfZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSkKCiMjIGxvYWQgcmVxdWlyZWQgcGFja2FnZQojbGlicmFyeShnZ2FsbHV2aWFsKQoKIyMgcGxvdApnZ3Bsb3QoZGZfYWxsdXZpYWwsIGFlcyh5ID0gdmFsdWUsIGF4aXMxID0gZnVsbF9jbHVzdGVycywgYXhpczIgPSBzZXhfY2x1c3RlcnMpKSArCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbCA9IHNleF9jbHVzdGVycyksCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAsIGtub3QucG9zID0gMCwgcmV2ZXJzZSA9IEZBTFNFKSArCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKwogIGdlb21fc3RyYXR1bSh3aWR0aCA9IDEvOCwgcmV2ZXJzZSA9IEZBTFNFKSArCiAgZ2VvbV90ZXh0KHN0YXQgPSAic3RyYXR1bSIsIGluZmVyLmxhYmVsID0gVFJVRSwgcmV2ZXJzZSA9IEZBTFNFKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MiwgbGFiZWxzID0gYygib3JpZ2luYWwgY2x1c3RlciIsICJTZXggQ2x1c3RlciIpKSArCiAgY29vcmRfZmxpcCgpICsKICBnZ3RpdGxlKCJDbHVzdGVyIElkZW50aWl0eSBpbiBmdWxsIGRhdGFzZXQgdnMuIHNleCBvbmx5IikgKwogICAgdGhlbWVfY2xhc3NpYygpCmBgYAoKIyMjIyBTaG93IHJlcHJlc2VudGF0aW9uIG9mIGdlbm90eXBlcyBwZXIgY2x1c3RlcgoKcHJlcCBmb3IgZG90cGxvdApgYGB7cn0KIyMgbWFrZSBhIGRhdGFmcmFtZSB0aGF0IGlzIHRoZSBtZXRhIGRhdGEKZGZfbWV0YV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhKQoKIyMgZGVmaW5lIG9yZGVyIGZvciBwbG90dGluZyAKbXlfbGV2ZWxzX3NleCA8LSBjKCIwIiwgIjkiLCAiMjgiLCAiMiIsICIyOSIsICIxNiIsICIyMiIsICIyMyIsICIxNSIsICIyMSIsICIzMCIsICI0IiwgIjMiLCAiMTgiLCAiNyIsICI4IiwgIjYiLCAiMjAiLCAiMTIiLCAiMjYiLCAiMTMiLCAiNSIsICIxMSIsICIyNSIsICIxIiwgIjE3IiwgIjEwIiwgIjI0IiwgIjE0IiwgIjI3IiwgIjE5IikKCiMjIHJlZGVmaW5lIG9yZGVyIG9mIGNsdXN0ZXJzOgpkZl9tZXRhX2RhdGEkc2V1cmF0X2NsdXN0ZXJzIDwtIGZhY3Rvcih4ID0gZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgbGV2ZWxzID0gbXlfbGV2ZWxzX3NleCkKCiMjIG1ha2UgYSBuZXcgZGYgb2YgQ0xVU1RFUiBhbmQgSURFTlRJVFkKZG90X3Bsb3RfZGYgPC0gYXMuZGF0YS5mcmFtZS5tYXRyaXgodGFibGUoZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgZGZfbWV0YV9kYXRhJGlkZW50aXR5X2NvbWJpbmVkKSkKZG90X3Bsb3RfZGYkY2x1c3RlciA8LSByb3duYW1lcyhkb3RfcGxvdF9kZikKCiMjIGNhbGN1bGF0ZSBwZXJjZW50YWdlIG9mIGNlbGxzIGZvciBlYWNoIGdlbm90eXBlCmRvdF9wbG90X2RmX3BjIDwtIChhcy5kYXRhLmZyYW1lLm1hdHJpeChwcm9wLnRhYmxlKHRhYmxlKGRmX21ldGFfZGF0YSRzZXVyYXRfY2x1c3RlcnMsIGRmX21ldGFfZGF0YSRpZGVudGl0eV9jb21iaW5lZCksIG1hcmdpbiA9IDIpKSAqIDEwMCkKCiMjIG1ha2UgYSBjb2x1bW4gZm9yIGNsdXN0ZXIgbmFtZXMKZG90X3Bsb3RfZGZfcGMkY2x1c3RlciA8LSByb3duYW1lcyhkb3RfcGxvdF9kZl9wYykKCiMjIG1lbHQgZGF0YWZyYW1lIGZvciBwbG90dGluZwpsaWJyYXJ5KHJlc2hhcGUyKQpkb3RfcGxvdF9kZl9wY19tZWx0ZWQgPC0gbWVsdChkb3RfcGxvdF9kZl9wYywgdmFyaWFibGUubmFtZSA9ICJjbHVzdGVyIikKY29sbmFtZXMoZG90X3Bsb3RfZGZfcGNfbWVsdGVkKVsyXSA8LSAiaWRlbnRpdHkiCgojIyBtZWx0IHRoZSByYXcgbnVtYmVyIHRvbwpkb3RfcGxvdF9kZl9tZWx0ZWQgPC0gbWVsdChkb3RfcGxvdF9kZiwgdmFyaWFibGUubmFtZSA9ICJjbHVzdGVyIikKY29sbmFtZXMoZG90X3Bsb3RfZGZfbWVsdGVkKVsyXSA8LSAiaWRlbnRpdHkiCmNvbG5hbWVzKGRvdF9wbG90X2RmX21lbHRlZClbM10gPC0gInJhd19udW1iZXIiCgojIyBtZXJnZSB0b2dldGhlcgppZGVudGljYWwoZG90X3Bsb3RfZGZfbWVsdGVkJGNsdXN0ZXIsIGRvdF9wbG90X2RmX3BjX21lbHRlZCRjbHVzdGVyKQpkb3RfcGxvdF9tZXJnZWQgPC0gY2JpbmQoZG90X3Bsb3RfZGZfbWVsdGVkLCBkb3RfcGxvdF9kZl9wY19tZWx0ZWQpCmRvdF9wbG90X21lcmdlZCA8LSBkb3RfcGxvdF9tZXJnZWRbLGMoMSwyLDMsNildCgojIyByZWRlZmluZSBvcmRlciBvZiBjbHVzdGVycwpkb3RfcGxvdF9tZXJnZWQkY2x1c3RlciA8LSBmYWN0b3IoeCA9IGRvdF9wbG90X21lcmdlZCRjbHVzdGVyLCBsZXZlbHMgPSBteV9sZXZlbHNfc2V4KQoKIyMgd2hlcmUgdmFsdWVzIGFyZSB6ZXJvLCBhZGQgTkEKIyMgZmluZCB3ZWxscyB3aGVyZSBpdCdzIHplcm8KemVyb192YWx1ZXMgPC0gZG90X3Bsb3RfbWVyZ2VkJHZhbHVlID09IDAKZG90X3Bsb3RfbWVyZ2VkJHZhbHVlW3plcm9fdmFsdWVzXSA8LSBOQQoKIyMgYWxzbyBkbyBmb3IgcmF3IG51bWJlcgp6ZXJvX3ZhbHVlcyA8LSBkb3RfcGxvdF9tZXJnZWQkcmF3X251bWJlciA9PSAwCmRvdF9wbG90X21lcmdlZCRyYXdfbnVtYmVyW3plcm9fdmFsdWVzXSA8LSBOQQoKIyMgcmVvcmRlciB4IGF4aXM6Cm15X2xldmVsc19nZW5vdHlwZSA8LSBjKCJHQ1NLTy1vb20iLCAiR0NTS08tMjkiLCAiR0NTS08tMiIsICJHQ1NLTy0xOSIsICJHQ1NLTy0zIiwgIkdDU0tPLTIxIiwgIkdDU0tPLTEzIiwgIkdDU0tPLTI4IiwgIkdDU0tPLTEwXzgyMCIsICJHQ1NLTy0xNyIsICJHQ1NLTy0yMCIsICJXVCIsICJXVF8xMFgiKQoKZG90X3Bsb3RfbWVyZ2VkJGlkZW50aXR5IDwtIGZhY3Rvcih4ID0gZG90X3Bsb3RfbWVyZ2VkJGlkZW50aXR5LCBsZXZlbHMgPSBteV9sZXZlbHNfZ2Vub3R5cGUpCmBgYAoKcGxvdApgYGB7ciwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodD0gN30KIyMgcGxvdApkb3RfcGxvdF9pZGVudGl0eSA8LSBnZ3Bsb3QoZG90X3Bsb3RfbWVyZ2VkLCBhZXMoeSA9IGZhY3RvcihjbHVzdGVyKSwgeCA9IGZhY3RvcihpZGVudGl0eSkpKSArCiAgICAgICMjIG1ha2UgaW50byBhIGRvdCBwbG90CiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG91cj12YWx1ZSwgc2l6ZT1yYXdfbnVtYmVyKSkgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93PSJibHVlIiwgaGlnaD0icmVkIiwgbGltaXRzPWMoIDAsIG1heChkb3RfcGxvdF9kZl9wY19tZWx0ZWQkdmFsdWUpKSwgbmEudmFsdWU9IndoaXRlIikgKwogICAgICAjY2hhbmdlIHRoZSBjb2xvdXJzCiAgICAgIHNjYWxlX2NvbG91cl92aXJpZGlzKG9wdGlvbiA9ICJpbmZlcm5vIiwgZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIikgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCksIHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYsICBmYW1pbHk9IkFyaWFsIikpICsKICAgICAgeWxhYigiQ2x1c3RlciIpICsKICAgICAgeGxhYigiSWRlbnRpdHkiKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEyLCBhbmdsZT00NSwgaGp1c3Q9MSwgdmp1c3Q9MSksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyLCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBwbG90Lm1hcmdpbiA9IHVuaXQoYygxLDMsMSwzKSwgImxpbmVzIikpICsKICAgICMjIGFubm90YXRlIG1hbGVzCiAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gNS41KSkgKwogICAgIyMgYW5ub3RhdGUgZmVtYWxlcwogICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDIwLjUpKSArCiAgICAjIyBhbm5vdGF0ZSBwaGVubyAxCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gNC41KSkgKwogICAgIyMgYW5ub3RhdGUgcGhlbm8gMgogICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IDUuNSkpICsgICAgCiAgICAjIyBhbm5vdGF0ZSBwaGVubyAzCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gNy41KSkgKwogICAgIyMgYW5ub3RhdGUgcGhlbm8gNAogICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IDExLjUpKQoKIyMgcHJpbnQKcHJpbnQoZG90X3Bsb3RfaWRlbnRpdHkpCmBgYAoKIyA0LiBTbGluZ3Nob3QgYW5kIFNDTUFQIHsudGFic2V0fQoKV2UgY2FuIHRoZW4gdXNlIFNsaW5nc2hvdCB0byBwbG90IGEgUHNldWRvdGltZSBhbmQgZXh0cmFjdCBtdXR1YWxseSBleGNsdXNpdmUgcGFydHMgb2YgdGhlIHRyYWplY3RvcnkgKE1hbGUgYW5kIEZlbWFsZSkgYXMgd2VsbCBhcyB0aGUgY29tbW9uIHN0YWxrIG9mIGJvdGggdHJhamVjdG9yaWVzLgoKIyMjIFNsaW5nc2hvdAoKcGFja2FnZXMKYGBge3J9CmxpYnJhcnkoc2xpbmdzaG90KQpsaWJyYXJ5KHNjYXRlcikKYGBgCgpEYXRhIEluCmBgYHtyfQojIyBleHRyYWN0IHRoZSBkYXRhIGZyb20gdGhlIG9iamVjdHMgYW5kIHNhdmUgdG8gZXhwb3J0IHRvIEFydGh1cgppbnRlZ3JhdGVkX3NleF9jb3VudHMgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAYXNzYXlzJGludGVncmF0ZWRAZGF0YQppbnRlZ3JhdGVkX3NleF9waGVubyA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEKI3NhdmVSRFMoaW50ZWdyYXRlZF9zZXhfY291bnRzLCBmaWxlPSJ+L2RhdGFfdG9fZXhwb3J0L2ludGVncmF0ZWRfc2V4X2NvdW50cy5SRFMiKQojc2F2ZVJEUyhpbnRlZ3JhdGVkX3NleF9waGVubywgZmlsZT0ifi9kYXRhX3RvX2V4cG9ydC9pbnRlZ3JhdGVkX3NleF9waGVuby5SRFMiKQojc2V4Y291bnQ8LXJlYWRSRFMoIi9Vc2Vycy90YWxtYW4vR29vZ2xlXCBEcml2ZS9BY3RpdmVTYW5nZXIvc2V4cGFwZXIvaW50ZWdyYXRlZF9zZXhfY291bnRzLlJEUyIpCiNzZXhwaGVubzwtcmVhZFJEUygiL1VzZXJzL3RhbG1hbi9Hb29nbGVcIERyaXZlL0FjdGl2ZVNhbmdlci9zZXhwYXBlci9pbnRlZ3JhdGVkX3NleF9waGVuby5SRFMiKQpzZXhjb3VudCA8LSBpbnRlZ3JhdGVkX3NleF9jb3VudHMKc2V4cGhlbm8gPC0gaW50ZWdyYXRlZF9zZXhfcGhlbm8KCiMjIHRlY2huaWNhbGx5IHRoaXMgaXMgYSBzaG9ydGN1dCBidXQgaXQgZGlkbid0IHdvcmsKIyNodHRwczovL3NhdGlqYWxhYi5vcmcvc2V1cmF0L3YzLjEvY29udmVyc2lvbl92aWduZXR0ZS5odG1sCiNjb252ZXJ0IFNldXJhdCB0byBTQ0Ugb2JqZWN0OgojcGJtYy5zY2UgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgpLCBhc3NheSA9ICJpbnRlZ3JhdGVkIikKYGBgCgojIyMjIHNsaW5nc2hvdCBvbiBQQ0EKUHJlcHJvY2VzcwpgYGB7cn0KIyMgbWFrZSBhIHNpbmdsZSBjZWxsIGV4cGVyaW1lbnQgb2JqZWN0LCB3aGljaCBpcyB0aGUgaW5wdXQgZm9yIFNsaW5nc2hvdApzZXhicmFuY2ggPC0gU2luZ2xlQ2VsbEV4cGVyaW1lbnQoYXNzYXlzID0gbGlzdCgKICBjb3VudHMgPSBhcy5tYXRyaXgoc2V4Y291bnQpLAogIGxvZ2NvdW50cyA9IGFzLm1hdHJpeChzZXhjb3VudCkKKSwgY29sRGF0YSA9IHNleHBoZW5vKQoKIyMgc3Vic2V0IHdpbGQtdHlwZSBjZWxscwpzZXhicmFuY2hXVDwtIHNleGJyYW5jaFssIGNvbERhdGEoc2V4YnJhbmNoKSRnZW5vdHlwZSA9PSAiV1QifGNvbERhdGEoc2V4YnJhbmNoKSRleHBlcmltZW50ID09ICJ0ZW54XzVrIl0KCiMjIGNhbGN1bGF0ZSB0aGUgUUMgbWV0cmljcwpzZXhicmFuY2hXVDwtY2FsY3VsYXRlUUNNZXRyaWNzKHNleGJyYW5jaFdUKQoKIyMgc2V0IHVwIHRoZSBjb2xvdXIgcGFsCm5iLmNvbHMgPC0gMTggCm15Y29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiU2V0MSIpKShuYi5jb2xzKQpgYGAKCkNhbGN1bGF0ZSB0aGUgUENTCmBgYHtyfQojIyBjYWxjdWxhdGUgUENBCnBjYSA8LSBwcmNvbXAodChhc3NheXMoc2V4YnJhbmNoV1QpJGNvdW50cyksIHNjYWxlLiA9IEZBTFNFKQoKIyMgc3Vic2V0IGNvb3JkaW5hdGVzCnJkMSA8LSBwY2EkeFssMToyXQoKIyMgcGxvdApwbG90KHJkMSwgY29sID0gcmdiKDAsMCwwLC41KSwgcGNoPTE2LCBhc3AgPSAyKQoKIyMgY2x1c3RlciB1c2luZyBrbWVhbnMKIyMgeW91IG5lZWQgdG8gc2V0IGEgc2VlZCBoZXJlIHRvIGVuc3VyZSB0aGUgcmVzdWx0cyBhcmUgcmVwcm9kdWNpYmxlCnNldC5zZWVkKDQyKQpjbDIgPC0ga21lYW5zKHJkMSwgY2VudGVycyA9IDEzKSRjbHVzdGVyCgojIyBwbG90CnBsb3QocmQxLCBjb2wgPSBteWNvbG9yc1tjbDJdLCBhc3AgPSAzLCBwY2ggPSAxNikKCiMjIG1ha2UgYSBuaWNlciBwbG90IHNvIHdlIGNhbiBpbnRlcnByZXQgdGhlIGNsdXN0ZXJzCmRmX3Bsb3R0aW5nIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQocmQxLCBjbDIpKQojIyBjaGFuZ2UgdG8gY2hhcmFjdGVyIHRvIG1ha2UgaXQgZGlzY3JldGUKZGZfcGxvdHRpbmckY2wyIDwtIGFzLmNoYXJhY3RlcihkZl9wbG90dGluZyRjbDIpCiMjIHBsb3QKZ2dwbG90KGRmX3Bsb3R0aW5nLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3VyID0gY2wyKSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHJhaW5ib3coMTMpKSArIAogIHRoZW1lX2NsYXNzaWMoKQpgYGAKCmBgYHtyfQojIyBpbml0aWFsaXNlIHBsb3QgdG8gcHJldmVudCBlcnJvcgpwbG90Lm5ldygpCgojIyBzbGluZ3Nob3QgdG8gZ2V0IGxpbmVhZ2VzCmxpbjEgPC0gZ2V0TGluZWFnZXMocmQxLCBjbDIsc3RhcnQuY2x1cyA9ICc4JykKCiMjIG1ha2UgYSBjdXJ2ZSB0aHJvdWdoIGxpbmVhZ2UgCmNydjEgPC0gZ2V0Q3VydmVzKGxpbjEpCgojIyBqb2luIHBvaW50cyB3aXRoIGxpbmUgc2VnbWVudHMgYW5kIHBsb3QKcGxvdChyZDEsIGNvbCA9IG15Y29sb3JzW2NsMl0sIGFzcCA9IDMsIHBjaCA9IDE2KQpsaW5lcyhjcnYxLCBsd2QgPSAzLCBjb2wgPSAnYmxhY2snKQoKIyMgYWRkIFBDQSBjb29yZGluYXRlcyB0byBTQ0Ugb2JqZWN0CnJlZHVjZWREaW1zKHNleGJyYW5jaFdUKSA8LSBTaW1wbGVMaXN0KFBDQSA9IHJkMSkKCiMjIGFkZCBjbHVzdGVycyB0byBTQ0Ugb2JqZWN0CnNleGJyYW5jaFdUJEdNTTwtY2wyCgojIyBBZGQgcHNldWRvdGltZXMgdG8gU0NFIG9iamVjdApzZXhicmFuY2hXVCRQVF9MaW5lYWdlRmVtYWxlPC1hcy5kYXRhLmZyYW1lKHNsaW5nUHNldWRvdGltZShjcnYxKSkkY3VydmUxCnNleGJyYW5jaFdUJFBUX0xpbmVhZ2VNYWxlPC1hcy5kYXRhLmZyYW1lKHNsaW5nUHNldWRvdGltZShjcnYxKSkkY3VydmUyCgojIyBhZGQgZGVzaWduYXRpb24gdG8gU0NFIG9iamVjdApzZXhicmFuY2hXVCRtYWxlPC1pcy5uYShzZXhicmFuY2hXVCRQVF9MaW5lYWdlRmVtYWxlKQpzZXhicmFuY2hXVCRmZW1hbGU8LWlzLm5hKHNleGJyYW5jaFdUJFBUX0xpbmVhZ2VNYWxlKQp2ZWMgPC0gdmVjdG9yKCkKZm9yIChpIGluIDE6bGVuZ3RoKHNleGJyYW5jaFdUJG1hbGUpKSB7CmlmIChzZXhicmFuY2hXVCRtYWxlW2ldID09IHNleGJyYW5jaFdUJGZlbWFsZVtpXSkge3ZlYzwtYyh2ZWMsInByZS1kZXQiKX0KICBpZiAoc2V4YnJhbmNoV1QkbWFsZVtpXSA9PSBUUlVFKSB7dmVjPC1jKHZlYywibWFsZSIpfQogIGlmIChzZXhicmFuY2hXVCRmZW1hbGVbaV0gPT0gVFJVRSkge3ZlYzwtYyh2ZWMsImZlbWFsZSIpfSAgCn0KCnNleGJyYW5jaFdUJHNleDwtdmVjCgojIyBwbG90IGNvbG91cmVkIGJ5IE5FSzMgKFBCQU5LQV8wNjAwNjAwKQpwbG90UENBKHNleGJyYW5jaFdULHNoYXBlX2J5PSJzZXgiLGNvbG91cl9ieT0iUEJBTktBLTA2MDA2MDAiKQpgYGAKCiMjIyMgc2xpbmdzaG90IG9uIFVNQVAKCmBgYHtyfQojIyBleHRyYWN0cyBvbmx5IDEweCBjZWxscyAKd3RfY2VsbHMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1RfMTBYIiksXSkKCiMjIG1ha2UgYSBuZXcgU2V1cmF0IG9mIHRoaXMKc2V1cmF0Lm9iamVjdCA8LVN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gd3RfY2VsbHMpCgojIyBnZXQgVU1BUCBjb29yZGluYXRlcwp1bWFwX2Nvb3JkcyA8LSBzZXVyYXQub2JqZWN0QHJlZHVjdGlvbnMkdW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhQGNlbGwuZW1iZWRkaW5ncwoKIyMgZ2V0IGNsdXN0ZXJzCiNjbHVzdGVycyA8LSBhcy5saXN0KHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy40KQojbmFtZXMoY2x1c3RlcnMpIDwtIHJvd25hbWVzKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhKQojY2x1c3RlcnMgPC0gYXMubGlzdChjbHVzdGVycykKIyMgY2x1c3RlciB1c2luZyBrbWVhbnMKIyMgeW91IG5lZWQgdG8gc2V0IGEgc2VlZCBoZXJlIHRvIGVuc3VyZSB0aGUgcmVzdWx0cyBhcmUgcmVwcm9kdWNpYmxlCnNldC5zZWVkKDQyKQpjbHVzdGVycyA8LSBrbWVhbnModW1hcF9jb29yZHMsIGNlbnRlcnMgPSAxMykkY2x1c3RlcgoKIyMgcGxvdAojIyBtYWtlIGEgbmljZXIgcGxvdCBzbyB3ZSBjYW4gaW50ZXJwcmV0IHRoZSBjbHVzdGVycwpkZl9wbG90dGluZyA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKHVtYXBfY29vcmRzLCBjbHVzdGVycykpCiMjIGNoYW5nZSB0byBjaGFyYWN0ZXIgdG8gbWFrZSBpdCBkaXNjcmV0ZQpkZl9wbG90dGluZyRjbHVzdGVycyA8LSBhcy5jaGFyYWN0ZXIoZGZfcGxvdHRpbmckY2x1c3RlcnMpCiMjIHBsb3QKZ2dwbG90KGRmX3Bsb3R0aW5nLCBhZXMoeCA9IHVtYXBvcHRpbWlzZWRfMSwgeSA9IHVtYXBvcHRpbWlzZWRfMiwgY29sb3VyID0gY2x1c3RlcnMpKSArIAogIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gcmFpbmJvdygxNSkpICsgCiAgdGhlbWVfY2xhc3NpYygpCgoKIyMgaW5pdGlhbGlzZSBwbG90IHRvIHByZXZlbnQgZXJyb3IKcGxvdC5uZXcoKQoKIyMgc2xpbmdzaG90IHRvIGdldCBsaW5lYWdlcwpsaW5lYWdlX3VhbXAgPC0gZ2V0TGluZWFnZXModW1hcF9jb29yZHMsIGNsdXN0ZXJzLCBzdGFydC5jbHVzID0gJzYnLCBlbmQuY2x1cyA9IGMoJzEnLCAnMTInKSkKCiMjIG1ha2UgYSBjdXJ2ZSB0aHJvdWdoIGxpbmVhZ2UgCmNydjEgPC0gZ2V0Q3VydmVzKGxpbmVhZ2VfdWFtcCkKCiMjIGpvaW4gcG9pbnRzIHdpdGggbGluZSBzZWdtZW50cyBhbmQgcGxvdApwbG90KHVtYXBfY29vcmRzLCBjb2wgPSBteWNvbG9yc1tjbHVzdGVyc10sIGFzcCA9IDMsIHBjaCA9IDE2KQpsaW5lcyhjcnYxLCBsd2QgPSAzLCBjb2wgPSAnYmxhY2snKQpgYGAKCkFkZCBkYXRhIHRvIFNldXJhdDoKYGBge3J9CiMjIGV4dHJhY3QgZGF0YSB0byBhZGQgdG8gU2V1cmF0CiMjIGV4dHJhY3QgY2x1c3RlcnMKbWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCA8LSBkYXRhLmZyYW1lKGNsdXN0ZXJzX2tfbWVhbnNfVU1BUCA9IGNsdXN0ZXJzKQojIyBBZGQgcHNldWRvdGltZXMKIyBjaGVjayB0aGUgbGVuZ3RoIG9mIGVhY2ggYnJhbmNoIHRvIHNlZSB3aGljaCBjdXJ2ZSBpcyB3aGljaCB1c2luZzogc3VtKGlzLm5hKGFzLmRhdGEuZnJhbWUoc2xpbmdQc2V1ZG90aW1lKGNydjEpKSRjdXJ2ZTEpKQojIHRoZW4gaW5zcGVjdCB1c2luZyB0aGUgZ2dwbG90MiBhYm92ZSB0byB3aGVyZSBtYWxlcyBhcmUgLSAKIyB0YWlsKGFzLmRhdGEuZnJhbWUoc2xpbmdQc2V1ZG90aW1lKGNydjEpKSwgMTAwKQojIHRhaWwobWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCwgMTAwKQptZXRhX2RhdGFfdG9fYWRkX2Zyb21fc2xpbmdzaG90JFBUX0ZlbWFsZV9VTUFQIDwtIGFzLmRhdGEuZnJhbWUoc2xpbmdQc2V1ZG90aW1lKGNydjEpKSRjdXJ2ZTEKbWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCRQVF9NYWxlX1VNQVAgPC0gYXMuZGF0YS5mcmFtZShzbGluZ1BzZXVkb3RpbWUoY3J2MSkpJGN1cnZlMgojIyBhZGQgZGVzaWduYXRpb24gdG8gU0NFIG9iamVjdAptZXRhX2RhdGFfdG9fYWRkX2Zyb21fc2xpbmdzaG90JHNleF9VTUFQIDwtICJwcmUtZGV0IgptZXRhX2RhdGFfdG9fYWRkX2Zyb21fc2xpbmdzaG90JHNleF9VTUFQW3doaWNoKGlzLm5hKG1ldGFfZGF0YV90b19hZGRfZnJvbV9zbGluZ3Nob3QkUFRfRmVtYWxlX1VNQVApKV0gPC0gIm1hbGUiCm1ldGFfZGF0YV90b19hZGRfZnJvbV9zbGluZ3Nob3Qkc2V4X1VNQVBbd2hpY2goaXMubmEobWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCRQVF9NYWxlX1VNQVApKV0gPC0gImZlbWFsZSIKCiMjIGlmIHRoZXJlIGFyZSAzIGN1cnZlcyBpbiBzbGluZ1BzZXVkb3RpbWUoY3J2MSk6CiNtZXRhX2RhdGFfdG9fYWRkX2Zyb21fc2xpbmdzaG90JHNleF9VTUFQW3doaWNoKGlzLm5hKG1ldGFfZGF0YV90b19hZGRfZnJvbV9zbGluZ3Nob3QkUFRfRmVtYWxlX1VNQVApICYgaXMubmEoYXMuZGF0YS5mcmFtZShzbGluZ1BzZXVkb3RpbWUoY3J2MSkpJGN1cnZlMykpXSA8LSAibWFsZSIKI21ldGFfZGF0YV90b19hZGRfZnJvbV9zbGluZ3Nob3Qkc2V4X1VNQVBbd2hpY2goaXMubmEobWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCRQVF9NYWxlX1VNQVApICYgaXMubmEoYXMuZGF0YS5mcmFtZShzbGluZ1BzZXVkb3RpbWUoY3J2MSkpJGN1cnZlMykpXSA8LSAiZmVtYWxlIgoKIyMgYWRkIGNsdXN0ZXJzIHRvIFNDRSBvYmplY3QKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXggPC0gQWRkTWV0YURhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIG1ldGFfZGF0YV90b19hZGRfZnJvbV9zbGluZ3Nob3QpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMH0KIyMgcGxvdApGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwuc2l6ZSA9IDUsIHB0LnNpemUgPSAwLjUsIGZlYXR1cmVzID0gYygiUFRfRmVtYWxlX1VNQVAiLCAiUFRfTWFsZV9VTUFQIikpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKCgpwbG90IHNleCBkZXNpZ25hdGlvbnMKYGBge3IsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDUsIHB0LnNpemUgPSAwLjUsIGdyb3VwLmJ5ID0gInNleF9VTUFQIiwgbmEudmFsdWUgPSAid2hpdGUiKSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3c9MyxieXJvdz1UUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQpgYGAKCiMjIyBTQ01BUAoKTG9hZCBwYWNrYWdlCmBgYHtyfQpsaWJyYXJ5KHNjbWFwKQpgYGAKClNldCB1cCBJbmRleApgYGB7cn0KI3RoZSByZWZlcmVuY2UgZGF0YXNldCBpczogc2V4YnJhbmNoV1QKIyMgc2V0IHVwIGEgZmVhdHVyZSBzeW1ib2wgY29sdW1uIGluIHRoZSBTQ0Ugb2JqZWN0CnJvd0RhdGEoc2V4YnJhbmNoV1QpJGZlYXR1cmVfc3ltYm9sIDwtIHJvd25hbWVzKHNleGJyYW5jaFdUKQoKIyMgbWFrZSBhbiBpc19leHByIGFzc2F5IHdoaWNoIG9ubHkgY291bnRzIHZhbHVlcyB3aXRoIG1vcmUgdGhhbiAwCmFzc2F5KHNleGJyYW5jaFdULCAiaXNfZXhwciIpIDwtIGNvdW50cyhzZXhicmFuY2hXVCkgPiAwCgojIyBTZWxlY3QgdGhlIHRvcCA1MDAgbW9zdCBpbXBvcnRhbnQgZ2VuZXMKc2V4YnJhbmNoV1QgPC0gc2VsZWN0RmVhdHVyZXMoc2V4YnJhbmNoV1QsIHN1cHByZXNzX3Bsb3QgPSBGQUxTRSwgbl9mZWF0dXJlcyA9IDUwMCkKCiMjIGluc3BlY3QgZmVhdHVyZXMgc2VsZWN0ZWQKdGFibGUocm93RGF0YShzZXhicmFuY2hXVCkkc2NtYXBfZmVhdHVyZXMpCgojIyBjcmVhdGUgcmVmZXJlbmNlIGluZGV4CnNleGJyYW5jaFdUIDwtIGluZGV4Q2VsbChzZXhicmFuY2hXVCkKCiMjIGluc3BlY3QgcmVzdWx0cwpuYW1lcyhtZXRhZGF0YShzZXhicmFuY2hXVCkkc2NtYXBfY2VsbF9pbmRleCkKbGVuZ3RoKG1ldGFkYXRhKHNleGJyYW5jaFdUKSRzY21hcF9jZWxsX2luZGV4JHN1YmNlbnRyb2lkcykKZGltKG1ldGFkYXRhKHNleGJyYW5jaFdUKSRzY21hcF9jZWxsX2luZGV4JHN1YmNlbnRyb2lkc1tbMV1dKQpgYGAKClF1ZXJ5IGRhdGFzZXQKYGBge3J9CiNxdWVyeSBkYXRhIHNldCBpcyBjYWxsZWQ6IHNleGJyYW5jaAp6IDwtIHNleGJyYW5jaAoKIyMgYWRkIGZlYXR1cmUgc3ltYm9sIHRvIFNDRSBvYmplY3QKcm93RGF0YSh6KSRmZWF0dXJlX3N5bWJvbCA8LSByb3duYW1lcyh6KQoKIyMgbWFwIGNlbGxzCnNjbWFwQ2VsbF9yZXN1bHRzIDwtIHNjbWFwQ2VsbCh6LCBsaXN0KHlhbiA9IG1ldGFkYXRhKHNleGJyYW5jaFdUKSRzY21hcF9jZWxsX2luZGV4KSkKCiMjIGNvcHkgb3ZlciBQQ0EgY29vcmRpbmF0ZQpjb2xEYXRhKHNleGJyYW5jaFdUKSRQQzE8LWFzLmRhdGEuZnJhbWUocmVkdWNlZERpbShzZXhicmFuY2hXVCkpJFBDMQpjb2xEYXRhKHNleGJyYW5jaFdUKSRQQzI8LWFzLmRhdGEuZnJhbWUocmVkdWNlZERpbShzZXhicmFuY2hXVCkpJFBDMgoKIyMgR2V0IG5lYXJlc3QgY2VsbCAtIHdoaWNoIGlzIGxvY2F0ZWQgaW4gdGhlIGZpcnN0IHJvdyBhbmQgbWFrZSBhIGxpc3QKZ2V0Y2VsbHMgPC0gc2NtYXBDZWxsX3Jlc3VsdHMkeWFuJGNlbGxzWzEsIF0KIyMgRXh0cmFjdCBtZXRhIGRhdGEgZm9yIHRoZXNlIGNlbGxzCmNkc2NlIDwtIGNvbERhdGEoc2V4YnJhbmNoV1QpW2dldGNlbGxzLCBdCiMjIEdldCBzaW1pbGFyaXR5IHNjb3Jlcwp0b3BzaW0gPC0gc2NtYXBDZWxsX3Jlc3VsdHMkeWFuJHNpbWlsYXJpdGllc1sxLCBdCgojIyBhZGQgbWV0YSBkYXRhIHRvIHF1ZXJ5IGRhdGFzZXQKIyBhZGQgbmVhcmVzdCBjZWxsCnokdG9wX3BiY2VsbCA8LSBnZXRjZWxscwojIyBhZGQgUENBIGNvb3JkaW5hdGVzCnokUEMxIDwtIGNkc2NlJFBDMQp6JFBDMiA8LSBjZHNjZSRQQzIKIyMgYWRkIGFzc2lnbmVkIHNleAp6JHNleDwtIGNkc2NlJHNleAojIyBhZGQgcHQKeiRQVF9MaW5lYWdlRmVtYWxlPC0gY2RzY2UkUFRfTGluZWFnZUZlbWFsZQp6JFBUX0xpbmVhZ2VNYWxlPC0gY2RzY2UkUFRfTGluZWFnZU1hbGUKIyMgYWRkIHNpbWlsYXJpdHkgc2NvcmUKeiR0b3BzaW0gPC0gdG9wc2ltCgojIyBpbnNwZWN0IHNpbWlsYXJpdHkgc2NvcmVzCmhpc3QoeiR0b3BzaW0pCgojIyBjb3VudCBhbnl0aGluZyB3aXRoIGEgc2ltaWxhcml0eSBzY29yZSBiZWxvdyAwLjQgYXMgdW5hc3NpZ25lZAp6JHRvcGNlbGxfc3BbeiR0b3BzaW0gPCAwLjRdIDwtICJ1bmFzc2lnbmVkIgp6JHRvcGNlbGxfc3AgPC0gYXMuZmFjdG9yKHokdG9wY2VsbF9zcCkKeiR5dDwtcmVwKCJhc3NpZ25lZCIsbGVuZ3RoKHokdG9wY2VsbF9zcCkpCnokeXRbeiR0b3BzaW0gPCAwLjRdIDwtICJ1bmFzc2lnbmVkIgoKIyMgZXh0cmFjdCBQQyBzY29yZXMKbm8gPC0gYXMuZGF0YS5mcmFtZShyZWR1Y2VkRGltKHNleGJyYW5jaFdUKVssMToyXSkKIyMgZXh0cmFjdCBtZXRhIGRhdGEKbnVtYmVyMiA8LSBhcy5kYXRhLmZyYW1lKGNkc2NlKQojIyBleHRyYWN0IHRvcCBjZWxsCm51bWJlcjIkdG9wY2VsbF9zcCA8LSB6JHl0CgojIyBwbG90CmdncGxvdChubywgYWVzKFBDMSwgUEMyKSkgKwogZ2VvbV9wb2ludChzaXplID0gMSxhbHBoYSA9IDEvMTApICsKIGdlb21fcG9pbnQoYWVzKHg9UEMxLCB5PVBDMixzaGFwZT1mYWN0b3IodG9wY2VsbF9zcCkpLCBkYXRhPW51bWJlcjIsIHNpemU9MiwgY29sb3VyPSJibGFjayIpICsKIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxLDIpKSsKIHNjYWxlX2NvbG9yX21hbnVhbCggdmFsdWVzID0gYygiMCIgPSAiIzFmNzdiNCIsIjEiID0iI2ZmN2YwZSIsIjIiID0iIzJjYTAyYyIsIjMsMCIgPSIjZDYyNzI4IiwiMywxIiA9IiM5NDY3YmQiLCIzLDIiPSIjOGM1NjRiIiwiMywzIj0iI2UzNzdjMiIsIjQiPSIjYmNiZDIyIiwiNSI9IiMxN2JlY2YiLCI2Ij0iI2FlYzdlOCIpKSArIGxhYnMoeD0iUEMxIiwgeT0iUEMyIikgCgojKwojICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTgpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSAjPSA4KSwgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OnN1bmdsYXNzZXM6LCBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpCgpgYGAKCiMjIyB0byBza2lwIHRoaXMgc2VjdGlvbiBhYm92ZSBhbmQganVzdCBnZXQgdGhlIGRhdGEgb3V0cHV0IGZyb20gQXJ0aHVyJ3Mgc2NyaXB0IHdoZXJlIFBDQSBpcyB1c2VkIGFzIHRoZSBiYXNlIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbjoKCnJlYWQgaW4gQXJ0aHVyJ3MgZGF0YQpgYGB7cn0KIyMgcmVhZCBpbiBkYXRhCmF0X2RhdGEgPC0gcmVhZFJEUygifi9kYXRhL3NleGJyYW5jaCIpCgojIyBleHRyYWN0IHZhbHVlcyBvZiBpbnRlcmVzdAphdF9tZXRhX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShhdF9kYXRhQGNvbERhdGEpCgojIyBsb29rIGF0IG5ldyBjb2xzOgpoZWFkKHRhYmxlKGF0X21ldGFfZGF0YSR0b3BfcGJjZWxsKSkKaGVhZCh0YWJsZShhdF9tZXRhX2RhdGEkdG9wc2ltKSkKaGVhZCh0YWJsZShhdF9tZXRhX2RhdGEkdG9wY2VsbF9zcCkpCmhlYWQodGFibGUoYXRfbWV0YV9kYXRhJHl0KSkKaGVhZCh0YWJsZShhdF9tZXRhX2RhdGEkc2V4KSkKI3RhYmxlKGF0X21ldGFfZGF0YSRQVF9MaW5lYWdlRmVtYWxlKQojdGFibGUoYXRfbWV0YV9kYXRhJFBUX0xpbmVhZ2VNYWxlKQpgYGAKCkFkZCBtZXRhIGRhdGEgdG8gU2V1cmF0IG9iamVjdApgYGB7cn0KY29sbmFtZXNfdG9fYWRkX3RvX21ldGFfZGF0YSA8LSBjKCJ0b3BfcGJjZWxsIiwgInRvcHNpbSIsICJ0b3BjZWxsX3NwIiwgInl0IiwgInNleCIsICJQVF9MaW5lYWdlRmVtYWxlIiwgIlBUX0xpbmVhZ2VNYWxlIikKCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIEFkZE1ldGFEYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBtZXRhZGF0YSA9IGF0X21ldGFfZGF0YVssd2hpY2goY29sbmFtZXMoYXRfbWV0YV9kYXRhKSAlaW4lIGNvbG5hbWVzX3RvX2FkZF90b19tZXRhX2RhdGEpXSwgY29sLm5hbWUgPSBjKCJhdF90b3BfcGJjZWxsIiwgImF0X3RvcHNpbSIsICJhdF90b3BjZWxsX3NwIiwgImF0X3l0IiwgImF0X3NleCIsICJhdF9QVF9MaW5lYWdlRmVtYWxlIiwgImF0X1BUX0xpbmVhZ2VNYWxlIikpCgojIyB0byByZW1vdmUgY29sdW1ucyBpbiBtZXRhZGF0YToKI3RlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVsxMzY6MTQ0XSA8LSBOVUxMCiN0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbWydOQU1FX09GX0NPTCddXSA8LSBOVUxMCmBgYAoKUGxvdCBzZXhlcwpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSwgZ3JvdXAuYnkgPSAiYXRfc2V4IikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDEwfQojIyB0aGUgc2xpbmdzaG90IHB0IHZhbHVlcyBoYXZlIE5BcyBmb3IgZS5nLiBtYWxlIGNlbGxzIGluIHRoZSBQVF9MaW5lYWdlRmVtYWxlLCB3ZSBjYW4gZGVhbCB3aXRoIHRoaXMgbGF0ZXIsIGJ1dCBmb3Igbm93LCB3ZSB3aWxsIGp1c3QgaWdub3JlIHRoaXMgYXMgRGltcGxvdCB3aWxsIG5vdCBwbG90IE5BIHZhbHVlcwojc3VtKGlzLm5hKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRhdF9QVF9MaW5lYWdlTWFsZSkpCiNzdW0oaXMubmEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJGF0X1BUX0xpbmVhZ2VGZW1hbGUpKQoKIyMgcGxvdApGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwuc2l6ZSA9IDUsIHB0LnNpemUgPSAwLjUsIGZlYXR1cmVzID0gYygiYXRfUFRfTGluZWFnZUZlbWFsZSIsICJhdF9QVF9MaW5lYWdlTWFsZSIpKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3c9MyxieXJvdz1UUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQpgYGAKCgojIyMjIENvbXBhcmlzb24gb2YgY2x1c3RlciB3YXkgb2YgY2FsbGluZyBtYWxlcyBhbmQgZmVtYWxlcyB2cy4gc2xpbmdzaG90OgoKYGBge3J9CnRhYmxlKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXgpCgptYWxlX2NsdXN0ZXJzIDwtIGMoIjEzIiwgIjUiLCAiMTEiLCAiMjUiLCAiMSIsICIxNyIsICIxMCIsICIyNCIsICIxNCIsICIyNyIsICIxOSIpCmZlbWFsZV9jbHVzdGVycyA8LSBjKCIxNiIsICIyMiIsICIyMyIsICIxNSIsICIyMSIsICIzMCIsICI0IiwgIjMiLCAiMTgiLCAiNyIsICI4IiwgIjYiLCAiMjAiLCAiMTIiLCAiMjYiKQphc2V4X2NsdXN0ZXJzIDwtIGMoIjAiLCAiOSIsICIyOCIsICIyIiwgIjI5IikKCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXhfZGVzaWduYXRpb25fdXNpbmdfY2x1c3RlcnMgPC0gTkEKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleF9kZXNpZ25hdGlvbl91c2luZ19jbHVzdGVyc1t3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzICVpbiUgbWFsZV9jbHVzdGVycyldIDwtICJNYWxlIgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4X2Rlc2lnbmF0aW9uX3VzaW5nX2NsdXN0ZXJzW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMgJWluJSBmZW1hbGVfY2x1c3RlcnMpXSA8LSAiRmVtYWxlIgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4X2Rlc2lnbmF0aW9uX3VzaW5nX2NsdXN0ZXJzW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMgJWluJSBhc2V4X2NsdXN0ZXJzKV0gPC0gIlByZS1kZXQiCgp0YWJsZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4X2Rlc2lnbmF0aW9uX3VzaW5nX2NsdXN0ZXJzKQpgYGAKCmBgYHtyfQp0YWJsZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4LCB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4X2Rlc2lnbmF0aW9uX3VzaW5nX2NsdXN0ZXJzKQpgYGAKClBsb3Qgc2V4ZXMKYGBge3IsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDUsIHB0LnNpemUgPSAwLjUsIGdyb3VwLmJ5ID0gInNleCIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKUGxvdCBzZXhlcwpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSwgZ3JvdXAuYnkgPSAic2V4X2Rlc2lnbmF0aW9uX3VzaW5nX2NsdXN0ZXJzIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKYGBgCgpjb3JyZWxhdGlvbiBvZiBtb25vY2xlIFBUIGFuZCAKCmBgYHtyfQojIyBleHRyYWN0IHBzZXVkb3RpbWUgdmFsdWVzOgpwdF92YWx1ZXMgPC0gYXMuZGF0YS5mcmFtZShwc2V1ZG90aW1lKG1vbm9jbGUub2JqZWN0LCByZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiKSkKcHRfdmFsdWVzJGNlbGxfbmFtZSA8LSByb3duYW1lcyhwdF92YWx1ZXMpCm1ldGFfZGF0YV9kZiA8LSBhcy5kYXRhLmZyYW1lKG1vbm9jbGUub2JqZWN0QGNvbERhdGEpCm1ldGFfZGF0YV9kZiRjZWxsX25hbWUgPC0gcm93bmFtZXMobWV0YV9kYXRhX2RmKQptZXRhX2RhdGFfZGYgPC0gbWVyZ2UobWV0YV9kYXRhX2RmLCBwdF92YWx1ZXMsIGJ5ID0gImNlbGxfbmFtZSIpCm5hbWVzKG1ldGFfZGF0YV9kZilbMTQyXTwtICJwdCIKCm1hbGVfcHRfY29ycmVsYXRpb25fZGYgPC0gbWV0YV9kYXRhX2RmW3doaWNoKG1ldGFfZGF0YV9kZiRjZWxsX25hbWUgJWluJSBtYWxlX2NlbGxzKSwgXQpmZW1hbGVfcHRfY29ycmVsYXRpb25fZGYgPC0gbWV0YV9kYXRhX2RmW3doaWNoKG1ldGFfZGF0YV9kZiRjZWxsX25hbWUgJWluJSBmZW1hbGVfY2VsbHMpLCBdCgpnZ3Bsb3QobWFsZV9wdF9jb3JyZWxhdGlvbl9kZiwgYWVzKHggPSBQVF9MaW5lYWdlTWFsZSwgeSA9IHB0LCBjb2xvdXIgPSBzZXgpKSArIAogIGdlb21fcG9pbnQoKSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgdGhlbWVfY2xhc3NpYygpCgpnZ3Bsb3QoZmVtYWxlX3B0X2NvcnJlbGF0aW9uX2RmLCBhZXMoeCA9IFBUX0xpbmVhZ2VGZW1hbGUsIHkgPSBwdCwgY29sb3VyID0gc2V4KSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgdGhlbWVfY2xhc3NpYygpCmBgYAoKYGBge3J9CmdncGxvdChtYWxlX3B0X2NvcnJlbGF0aW9uX2RmLCBhZXMoeCA9IFBUX0ZlbWFsZV9VTUFQLCB5ID0gcHQpKSArIAogIGdlb21fcG9pbnQoKSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgdGhlbWVfY2xhc3NpYygpCmBgYAoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCiMgU2F2ZSBhbmQgRXhwb3J0IHsudGFic2V0fQoKc2F2ZSBlbnZpcm9ubWVudApgYGB7cn0KIyMgVGhpcyBzYXZlcyBldmVyeXRoaW5nIGluIHRoZSBnbG9iYWwgZW52aXJvbm1lbnQgZm9yIGVhc3kgcmVjYWxsIGxhdGVyCiNzYXZlLmltYWdlKGZpbGUgPSAiR0NTS09fU2V4X0JyYW5jaF9BbmFseXNpcy5SRGF0YSIpCiNsb2FkKGZpbGUgPSAiR0NTS09fU2V4X0JyYW5jaF9BbmFseXNpcy5SRGF0YSIpCmBgYAoKc2F2ZSBtb2R1bGVzCmBgYHtyfQojZ2VuZV9tb2R1bGVfZGZfc2V4CndyaXRlLmNzdihnZW5lX21vZHVsZV9kZl9zZXgsIGZpbGUgPSAiLi4vZGF0YV90b19leHBvcnQvZ2VuZV9tb2R1bGVfZGZfc2V4LmNzdiIpCiNzYXZlKHBiXzMwa19zZXhfZmlsdGVyZWQsIHBiX3NleF9maWx0ZXJlZCwgZmlsZSA9ICJQYXJ0XzJfaW5wdXQuUmRhdGEiKQpgYGAKClNhdmUgb2JqZWN0KHMpCmBgYHtyfQojIyBzYXZlIGludGVncmF0ZWQgb2JqZWN0IHRvIGZpbGUKI3NhdmVSRFModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGZpbGUgPSAiLi4vZGF0YV90b19leHBvcnQvdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgucHJvY2Vzc2VkLlJEUyIpIAojIyByZXN0b3JlIHRoZSBvYmplY3QKI3RlbngubXV0YW50LmludGVncmF0ZWQgPC0gcmVhZFJEUygiLi4vZGF0YV90b19leHBvcnQvdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgucHJvY2Vzc2VkLlJEUyIpCmBgYAoKIyBBcHBlbmRpeCB7LnRhYnNldH0KCiMjIyBGdW5jdGlvbnMgSW5mbwoKYGBge3J9ClNldXJhdDo6OkRvSGVhdG1hcApgYGAKCmBgYHtyfQptb25vY2xlOjo6cGxvdF9wc2V1ZG90aW1lX2hlYXRtYXAKYGBgCgpgYGB7cn0KZ2V0QW55d2hlcmUoYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbikKYGBgCgpzbyBlc3NlbnRpYWxseSBpdCBmaXJzdCB0YWtlcyB0aGUgY291bnRzIG1hdHJpeCBhbmQgc3Vic2V0cyBpdCBieSB5b3VyIGdlbmUgZ3JvdXBzLCB0aGVuIGl0IHN1bXMgdGhlIHZhbHVlcyAtIGlmIHlvdSBzcGVjaWZ5IHNjYWxlIHRoZW4gaXQgd2lsbCBjYWxjdWFsdGUgdGhlIHogc2NvcmUgb2YgdGhlIHRyYW5zZm9ybWVkIGRhdGFmcmFtZSAKCgoKCgoKCiMjIEEuIERpZmZ1c2lvbiBNYXAKCmNvbnN0cnVjdCBtYXAKYGBge3J9CiMjIGNvbnN0cnVjdCBkaWZmdXNpb24gbWFwCiMjIGh0dHA6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9kZXZlbC9iaW9jL3ZpZ25ldHRlcy9zbGluZ3Nob3QvaW5zdC9kb2MvdmlnbmV0dGUuaHRtbAojIyBpbnB1dCBpcyBhIHRyYW5zZm9ybWVkIGV4cHJlc3Npb24gbWF0cml4IChnZW5lcyBhcyBjb2xzIGFuZCBjZWxscyBhcyByb3dzKQpkbSA8LSBEaWZmdXNpb25NYXAodChhcy5kYXRhLmZyYW1lKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QGFzc2F5cyRpbnRlZ3JhdGVkQGRhdGEpKSkKCiMjIGV4dHJhY3QgbWV0YSBkYXRhIGZvciBwbG90dGluZwpkZl9tZXRhX2RhdGEgPC0gKGFzLmRhdGEuZnJhbWUodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhKSkKCiMjIG1ha2UgY29tYmluZWQgZGF0YWZyYW1lCnJkMiA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKERDMSA9IGRtJERDMSwgREMyID0gZG0kREMyLCBpZGVudGl0eSA9IGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHBvc3RfaW50ZWdyYXRpb25fY2x1c3RlcnMpKSkpCgojIyBwbG90CmdncGxvdChyZDIsIGFlcyh4ID0gREMxLCB5ID0gREMyLCBjb2xvdXIgPSBhcy5jaGFyYWN0ZXIoaWRlbnRpdHkpKSkgKyBnZW9tX3BvaW50KHNpemUgPSAxKSArIAogIHRoZW1lKGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZV9jbGFzc2ljKCkKYGBgCgoKCgoKCgoKCgoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gM30KIyMgbWFrZSBhIGRlbnNpdHkgcGxvdCBmb3IgcmVhbCB0aW1lIGNvcnJlbGF0aW9ucyB1c2luZyBrYXNpYSBkYXRhCiMjIG1ha2UgYW4gYW5ub3RhdGlvbiBkYXRhZnJhbWUKYW5ub19yZWFsX3RpbWUgPC0gZGF0YS5mcmFtZShtb25vY2xlLm9iamVjdEBjb2xEYXRhJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUsIG1vbm9jbGUub2JqZWN0QGNvbERhdGEkcHQsIG1vbm9jbGUub2JqZWN0QGNvbERhdGEkUHJlZGljdGlvbi5TcGVhcm1hbi5fS2FzaWEsIHJvdy5uYW1lcyA9IHJvd25hbWVzKG1vbm9jbGUub2JqZWN0QGNvbERhdGEpKQpuYW1lcyhhbm5vX3JlYWxfdGltZSkgPC0gYygic2V4IiwgIlBzZXVkb3RpbWUiLCAicmVhbF90aW1lIikKCiMjIGNoYW5nZSB0aGUgb3JkZXIgb2YgdGhlIGNvbHMgKGNlbGxzKSBpbiBkYXRhIGZyYW1lCmNvbC5vcmRlciA8LSByb3duYW1lcyhhbm5vX3JlYWxfdGltZVt3aXRoKGFubm9fcmVhbF90aW1lLCBvcmRlcihzZXgsIFBzZXVkb3RpbWUpKSwgXSkKYW5ub19yZWFsX3RpbWUgPC0gYW5ub19yZWFsX3RpbWVbY29sLm9yZGVyLF0KCiMjIGFkZCBhbiAib3JkZXIiIGNvbCB0byB0aGUgZGF0YWZyYW1lIHRvIGFzc2lzdCBpbiBwbG90dGluZwphbm5vX3JlYWxfdGltZSRvcmRlciA8LSBjKDE6bnJvdyhhbm5vX3JlYWxfdGltZSkpCgojIyMjIHBsb3QgZGVuc2l0eSBwbG90IHgKZGVuczEgPC0gZ2dwbG90KGFubm9fcmVhbF90aW1lLCBhZXMoeCA9IG9yZGVyLCBmaWxsID0gYXMuZmFjdG9yKHJlYWxfdGltZSkpKSArIAogICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4yKSArCiAgICAgICAgICAgICAgICAjdGhlbWVfdm9pZCgpICsgCiAgICAgICAgICAgICAgICAjdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICAgICAgICAgICAgICAgIyMgYWRkIGFubm90YXRpb25zIGZvciBzZXgKICAgICAgZ2VvbV9yZWN0KGRhdGEgPSBjbHVzdGVyX2Fubm8sIG1hcHBpbmc9YWVzKHhtaW49eDEsIHhtYXg9eDIsIHltaW49eTEsIHltYXg9eTIsIGZpbGw9TWVkaWFuX1BzZXVkb3RpbWVfb2ZfQ2x1c3RlciksIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiKSArCiAgIyMgZmxpcCBjb29yZGluYXRlcyAKICAjIyBnZW9tcyBiZWxvdyB3aWxsIHVzZSBhbm90aGVyIGNvbG9yIHNjYWxlCiAgICBuZXdfc2NhbGVfZmlsbCgpICsKICAgIGdlb21fcmVjdChkYXRhID0gY2x1c3Rlcl9hbm5vLCBtYXBwaW5nPWFlcyh4bWluPUJ4MSwgeG1heD1CeDIsIHltaW49QnkxLCB5bWF4PUJ5MiwgZmlsbD1JZGVudGl0eSksIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk1hbGUiID0iIzAxNmMwMCIsICJGZW1hbGUiPSIjYTUyYjFlIiwgIkFzZXh1YWwiPSAiIzAwNTJjNSIsICJDb21taXR0ZWQiID0gIiNmMmViMjMiKSkKCmRlbnMxCgpgYGAK